Skip to content

Commit

Permalink
feat: #186 support paste event
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Mar 27, 2024
1 parent 0ed9718 commit dced051
Show file tree
Hide file tree
Showing 24 changed files with 293 additions and 161 deletions.
4 changes: 2 additions & 2 deletions libs/Universal-PicGo-Core/src/index.ts
Expand Up @@ -17,12 +17,12 @@ import {
IUploaderConfigListItem,
IPluginConfig,
} from "./types"
import { isFileOrBlob } from "./utils/common"
import { isFileOrBlob, calculateMD5 } from "./utils/common"

export { UniversalPicGo, ExternalPicgo, eventBus }
export { ConfigDb, PluginLoaderDb, ExternalPicgoConfigDb }
export { PicgoTypeEnum, IBusEvent }
export { isFileOrBlob }
export { isFileOrBlob, calculateMD5 }
export { win, currentWin, parentWin, hasNodeEnv }
export {
type IPicGo,
Expand Down
Expand Up @@ -10,16 +10,11 @@
import crypto from "crypto"
import { ILocalesKey } from "../../../i18n/zh-CN"
import { IPicGo, IPluginConfig, IUpyunConfig } from "../../../types"
import { base64ToBuffer } from "../../../utils/common"
import { base64ToBuffer, calculateMD5 } from "../../../utils/common"
import { IBuildInEvent } from "../../../utils/enums"
import { Buffer } from "../../../utils/nodePolyfill"
import { AxiosRequestConfig } from "axios"

// 封装计算MD5哈希的方法
function calculateMD5(input: string) {
return crypto.createHash("md5").update(input).digest("hex")
}

function hmacsha1(secret: string, value: string) {
return crypto.createHmac("sha1", secret).update(value, "utf8").digest().toString("base64")
}
Expand Down
4 changes: 4 additions & 0 deletions libs/Universal-PicGo-Core/src/utils/common.ts
Expand Up @@ -12,6 +12,7 @@ import { hasNodeEnv, win } from "universal-picgo-store"
import imageSize from "./image-size"
import { calculateHash } from "./hashUtil"
import { Buffer } from "./nodePolyfill"
import crypto from "crypto"

export const isUrl = (url: string): boolean => url.startsWith("http://") || url.startsWith("https://")

Expand Down Expand Up @@ -442,3 +443,6 @@ export const getImageSize = (file: Buffer | typeof win.Buffer): IImgSize => {
}
}
}

// 封装计算MD5哈希的方法
export const calculateMD5 = (input: string) => crypto.createHash("md5").update(input).digest("hex")
16 changes: 11 additions & 5 deletions libs/zhi-siyuan-picgo/src/index.ts
Expand Up @@ -7,26 +7,32 @@
* of this license document, but changing it is not allowed.
*/

import { SiyuanPicGo } from "./lib/siyuanPicgo"
import { SiyuanPicgoPostApi } from "./lib/siyuanPicgoPostApi"
import {
calculateMD5,
ConfigDb,
ExternalPicgoConfigDb,
IConfig,
IExternalPicgoConfig,
IImgInfo,
IPicGo,
IPicgoDb,
IConfig,
IPluginConfig,
PicgoTypeEnum,
PluginLoaderDb,
IPluginConfig,
} from "universal-picgo"
import { SiyuanConfig as SiyuanPicgoConfig } from "zhi-siyuan-api"
import { PicgoHelper } from "./lib/picgoHelper"
import { retrieveImageFromClipboardAsBlob } from "./lib/utils/browserClipboard"
import { copyToClipboardInBrowser } from "./lib/utils/utils"
import { copyToClipboardInBrowser, generateUniqueName } from "./lib/utils/utils"
import { ImageItem } from "./lib/models/ImageItem"
import { ImageParser } from "./lib/parser/ImageParser"
import { ParsedImage } from "./lib/models/ParsedImage"

export { SiyuanPicgoConfig, SiyuanPicgoPostApi, PicgoHelper }
export { retrieveImageFromClipboardAsBlob, copyToClipboardInBrowser }
export { SiyuanPicGo, SiyuanPicgoConfig, SiyuanPicgoPostApi, PicgoHelper }
export { ImageItem, ImageParser, ParsedImage }
export { retrieveImageFromClipboardAsBlob, copyToClipboardInBrowser, calculateMD5, generateUniqueName }
export { ConfigDb, PluginLoaderDb, ExternalPicgoConfigDb }
export { PicgoTypeEnum }
export { type IPicGo, type IImgInfo, type IPicgoDb, type IConfig, type IExternalPicgoConfig, type IPluginConfig }
50 changes: 50 additions & 0 deletions libs/zhi-siyuan-picgo/src/lib/siyuanPicgo.ts
@@ -0,0 +1,50 @@
/*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* Copyright (C) 2024 Terwer, Inc. <https://terwer.space/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/

import { SiyuanPicgoPostApi } from "./siyuanPicgoPostApi"
import { SiyuanConfig, SiyuanKernelApi } from "zhi-siyuan-api"

/**
* 思源笔记 PicGo 实例
*/
class SiyuanPicGo {
public static async getInstance(siyuanConfig: SiyuanConfig, isDev?: boolean): Promise<SiyuanPicgoPostApi> {
return new Promise((resolve, _reject) => {
const siyuanApi = new SiyuanKernelApi(siyuanConfig)
const picgo = new SiyuanPicgoPostApi(siyuanConfig, isDev)

let needUpdate = false
const checkConfig = () => {
if (picgo.cfgUpdating) {
needUpdate = true
siyuanApi.pushMsg({
msg: "检测到旧配置,正在迁移配置,请勿进行任何操作...",
timeout: 1000,
})
console.warn("检测到旧配置,正在迁移配置,请勿进行任何操作...")
setTimeout(checkConfig, 1000)
} else {
if (needUpdate) {
siyuanApi.pushMsg({
msg: "PicGO 图床历史配置迁移完成",
timeout: 7000,
})
console.log("PicGO 图床历史配置迁移完成")
needUpdate = false
}
console.log("picgo instance is ready")
resolve(picgo)
}
}
checkConfig()
})
}
}

export { SiyuanPicGo }
61 changes: 33 additions & 28 deletions libs/zhi-siyuan-picgo/src/lib/siyuanPicgoPostApi.ts
Expand Up @@ -9,7 +9,7 @@

import { ILogger, simpleLogger } from "zhi-lib-base"
import { SiyuanPicGoUploadApi } from "./siyuanPicGoUploadApi"
import { hasNodeEnv, IImgInfo, IPicGo, win } from "universal-picgo"
import { hasNodeEnv, IPicGo, isFileOrBlob, win } from "universal-picgo"
import { ParsedImage } from "./models/ParsedImage"
import { ImageItem } from "./models/ImageItem"
import { SIYUAN_PICGO_FILE_MAP_KEY } from "./constants"
Expand All @@ -18,15 +18,15 @@ import { SiyuanConfig, SiyuanKernelApi } from "zhi-siyuan-api"
import { ImageParser } from "./parser/ImageParser"
import { PicgoPostResult } from "./models/PicgoPostResult"
import { DeviceDetection, DeviceTypeEnum, SiyuanDevice } from "zhi-device"
import { isFileOrBlob } from "universal-picgo"
import { IImgInfo } from "universal-picgo/src"

/**
* Picgo与文章交互的通用方法
*/
class SiyuanPicgoPostApi {
private readonly logger: ILogger
private readonly imageParser: ImageParser
private readonly siyuanApi: SiyuanKernelApi
public readonly siyuanApi: SiyuanKernelApi
private readonly siyuanConfig: SiyuanConfig
private readonly isSiyuanOrSiyuanNewWin: boolean
private readonly picgoApi: SiyuanPicGoUploadApi
Expand Down Expand Up @@ -71,7 +71,7 @@ class SiyuanPicgoPostApi {
*
* @param input 路径数组,可为空,为空上传剪贴板
*/
public async upload(input?: any[]): Promise<IImgInfo[] | Error> {
public async originalUpload(input?: any[]): Promise<IImgInfo[] | Error> {
return this.picgoApi.upload(input)
}

Expand Down Expand Up @@ -129,8 +129,10 @@ class SiyuanPicgoPostApi {
return ret
}

// ===================================================================================================================

/**
* 上传当前文章图片到图床(提供给外部调用)
* 上传当前文章图片到图床(单篇文档所有图片全部批量上传,提供给外部调用)
*
* @param pageId 文章ID
* @param attrs 文章属性
Expand Down Expand Up @@ -223,7 +225,7 @@ class SiyuanPicgoPostApi {
}

/**
* 上传单张图片到图床
* 上传单张图片到图床(当前图片单个上传,提供给外部调用)
*
* @param pageId 文章ID
* @param attrs 文章属性
Expand All @@ -247,34 +249,37 @@ class SiyuanPicgoPostApi {
return
}

let imageFullPath: string
// blob 或者 file 直接上传
if (isFileOrBlob(imageItem.url)) {
imageFullPath = imageItem.url
} else {
if (this.isSiyuanOrSiyuanNewWin) {
// 如果是路径解析路径
const win = SiyuanDevice.siyuanWindow()
const dataDir: string = win.siyuan.config.system.dataDir
imageFullPath = `${dataDir}/assets/${imageItem.name}`
this.logger.info(`Will upload picture from ${imageFullPath}, imageItem =>`, imageItem)

const fs = win.require("fs")
if (!fs.existsSync(imageFullPath)) {
// 路径不存在直接上传
// 兼容剪贴板
if (!StrUtil.isEmptyString(imageItem.url)) {
let imageFullPath: string
// blob 或者 file 直接上传
if (isFileOrBlob(imageItem.url)) {
imageFullPath = imageItem.url
} else {
if (this.isSiyuanOrSiyuanNewWin) {
// 如果是路径解析路径
const win = SiyuanDevice.siyuanWindow()
const dataDir: string = win.siyuan.config.system.dataDir
imageFullPath = `${dataDir}/assets/${imageItem.name}`
this.logger.info(`Will upload picture from ${imageFullPath}, imageItem =>`, imageItem)

const fs = win.require("fs")
if (!fs.existsSync(imageFullPath)) {
// 路径不存在直接上传
imageFullPath = imageItem.url
}
} else {
// 浏览器环境直接上传
imageFullPath = imageItem.url
}
} else {
// 浏览器环境直接上传
imageFullPath = imageItem.url
}
}

this.logger.warn("isSiyuanOrSiyuanNewWin=>" + this.isSiyuanOrSiyuanNewWin + ", imageFullPath=>", imageFullPath)
filePaths.push(imageFullPath)
this.logger.warn("isSiyuanOrSiyuanNewWin=>" + this.isSiyuanOrSiyuanNewWin + ", imageFullPath=>", imageFullPath)
filePaths.push(imageFullPath)
}

// 批量上传
const imageJson: any = await this.picgoApi.upload(filePaths)
const imageJson: any = await this.originalUpload(filePaths)
this.logger.debug("图片上传完成,imageJson=>", imageJson)
const imageJsonObj = JsonUtil.safeParse(imageJson, []) as any
// 处理后续
Expand Down
11 changes: 2 additions & 9 deletions libs/zhi-siyuan-picgo/src/lib/utils/md5Util.ts
Expand Up @@ -7,20 +7,13 @@
* of this license document, but changing it is not allowed.
*/

import { md5 } from "js-md5"
import { calculateMD5 } from "universal-picgo"

/**
* 获取文件名的hash
*
* @param filename 文件名
*/
export const getFileHash = (filename: string): string => {
// import { createHash } from "crypto"
// const hash = createHash("sha256")
// hash.update(filename)
// return hash.digest("hex")

// Base64.toBase64(filename).substring(0, 8);

return md5(filename)
return calculateMD5(filename)
}
17 changes: 17 additions & 0 deletions libs/zhi-siyuan-picgo/src/lib/utils/utils.ts
Expand Up @@ -85,3 +85,20 @@ export const trimValues = (obj: any) => {
})
return newObj
}

export function generateUniqueName() {
const currentTime = Math.floor(Date.now() / 1000) // 获取当前时间戳(秒级)

function generateRandomString(length: number) {
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
let randomString = ""
for (let i = 0; i < length; i++) {
randomString += characters.charAt(Math.floor(Math.random() * characters.length))
}
return randomString
}

const randomString = generateRandomString(6) // 生成长度为6的随机字符串
const uniqueName = `${currentTime}_${randomString}`
return uniqueName + ".png"
}
Expand Up @@ -10,13 +10,11 @@
<script setup lang="ts">
import { UploadFilled } from "@element-plus/icons-vue"
import { onBeforeMount, onBeforeUnmount, reactive, ref } from "vue"
import { SiyuanPicGo } from "@/utils/siyuanPicgo.ts"
import { ElMessage, UploadRequestOptions } from "element-plus"
import { retrieveImageFromClipboardAsBlob } from "zhi-siyuan-picgo"
import { generateUniqueName, ImageItem, retrieveImageFromClipboardAsBlob } from "zhi-siyuan-picgo"
import { useVueI18n } from "$composables/useVueI18n.ts"
import { createAppLogger } from "@/utils/appLogger.ts"
import { usePicgoUpload } from "$composables/usePicgoUpload.ts"
import { ImageItem } from "zhi-siyuan-picgo/src/lib/models/ImageItem.ts"
const logger = createAppLogger("drag-upload")
Expand Down Expand Up @@ -53,7 +51,7 @@ const handleDragAction = async (file: Blob) => {
try {
formData.picgoCommonData.isUploadLoading = true
const imageItem = new ImageItem("", file as any, true, "", "")
const imageItem = new ImageItem(generateUniqueName(), file as any, true, "", "")
await picgoUploadMethods.doUploadImageToBed(imageItem)
res = {
Expand Down
Expand Up @@ -8,9 +8,8 @@
-->

<script setup lang="ts">
import { ImageItem } from "zhi-siyuan-picgo/src/lib/models/ImageItem.ts"
import { copyToClipboardInBrowser, ImageItem } from "zhi-siyuan-picgo"
import { BrowserUtil } from "zhi-device"
import { copyToClipboardInBrowser } from "zhi-siyuan-picgo"
import { useVueI18n } from "$composables/useVueI18n.ts"
import { reactive } from "vue"
Expand All @@ -24,14 +23,14 @@ enum UrlTypeEnum {
const props = defineProps({
imgInfo: {
type: Object,
default: {} as ImageItem,
},
default: {} as ImageItem
}
})
// uses
const { t } = useVueI18n()
const formData = reactive({
urlType: UrlTypeEnum.MD,
urlType: UrlTypeEnum.MD
})
const doCopy = (str: string) => {
Expand Down Expand Up @@ -110,6 +109,7 @@ const onImageUrlCopy = (imageInfo: ImageItem, type: UrlTypeEnum) => {
.url-copy-group
width 100%
margin-right 2px
.copy-action-item
width 25%
</style>
Expand Up @@ -12,14 +12,14 @@ import { useVueI18n } from "$composables/useVueI18n.ts"
import { reactive } from "vue"
import { PicgoTypeEnum } from "zhi-siyuan-picgo"
import { useExternalPicGoSetting } from "@/stores/useExternalPicGoSetting.ts"
import { SiyuanPicGo } from "@/utils/siyuanPicgo.ts"
import { useBundledPicGoSetting } from "@/stores/useBundledPicGoSetting.ts"
import { SiyuanPicGoClient } from "@/utils/SiyuanPicGoClient.ts"
const { t } = useVueI18n()
const { getBundledPicGoSetting } = useBundledPicGoSetting()
const { getExternalPicGoSetting } = useExternalPicGoSetting()
const siyuanPicgo = await SiyuanPicGo.getInstance()
const siyuanPicgo = await SiyuanPicGoClient.getInstance()
const ctx = siyuanPicgo.ctx()
const bundledPicGoSettingForm = getBundledPicGoSetting(ctx)
const externalPicGoSettingForm = getExternalPicGoSetting(ctx)
Expand All @@ -28,17 +28,17 @@ const formData = reactive({
picgoTypeList: [
{
value: PicgoTypeEnum.Bundled,
label: t("upload.adaptor.bundled"),
label: t("upload.adaptor.bundled")
},
{
value: PicgoTypeEnum.App,
label: t("upload.adaptor.app"),
},
label: t("upload.adaptor.app")
}
// {
// value: PicgoTypeEnum.Core,
// label: t("upload.adaptor.core"),
// },
],
]
})
const handlePicgoTypeChange = (val: any) => {
Expand Down

0 comments on commit dced051

Please sign in to comment.