Skip to content

Commit

Permalink
fix: 兼容平台图片上传-Picgo 插件检测
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Aug 14, 2023
1 parent a83a216 commit 090425c
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 38 deletions.
7 changes: 6 additions & 1 deletion src/adaptors/api/hexo/hexoApiAdaptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ import { HexoYamlConverterAdaptor } from "~/src/adaptors/api/hexo/hexoYamlConver
* @since 0.8.1
*/
class HexoApiAdaptor extends CommonGithubApiAdaptor {
public async preEditPost(post: Post, dynCfg: any): Promise<Post> {
public async preEditPost(post: Post, id?: string, publishCfg?: any): Promise<Post> {
// 调用父类预处理
await super.preEditPost(post, id, publishCfg)
this.logger.info("handled preEditPost with parent")

// 处理 YAML
const cfg = this.cfg as CommonGithubConfig
const yamlApi: YamlConvertAdaptor = new HexoYamlConverterAdaptor()
const yamlObj: YamlFormatObj = yamlApi.convertToYaml(post, cfg)
Expand Down
102 changes: 65 additions & 37 deletions src/adaptors/base/baseExtendApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ import { usePicgoBridge } from "~/src/composables/usePicgoBridge.ts"
import { base64ToBuffer, remoteImageToBase64Info, toBase64Info } from "~/src/utils/polyfillUtils.ts"
import { StrUtil } from "zhi-common"
import { useSiyuanDevice } from "~/src/composables/useSiyuanDevice.ts"
import { isFileExists } from "~/src/utils/siyuanUtils.ts"
import { useSiyuanApi } from "~/src/composables/useSiyuanApi.ts"
import { SiyuanKernelApi } from "zhi-siyuan-api"
import { DynamicConfig } from "~/src/platforms/dynamicConfig.ts"

/**
* 各种模式共享的扩展基类
Expand All @@ -46,6 +50,7 @@ class BaseExtendApi extends WebApi implements IBlogApi, IWebApi {
private readonly api: BaseBlogApi | BaseWebApi
protected readonly picgoBridge: any
private readonly isSiyuanOrSiyuanNewWin: boolean
private readonly kernelApi: SiyuanKernelApi

constructor(api: BaseBlogApi | BaseWebApi) {
super()
Expand All @@ -55,58 +60,81 @@ class BaseExtendApi extends WebApi implements IBlogApi, IWebApi {
this.picgoBridge = usePicgoBridge()
const { isInSiyuanOrSiyuanNewWin } = useSiyuanDevice()
this.isSiyuanOrSiyuanNewWin = isInSiyuanOrSiyuanNewWin()
const { kernelApi } = useSiyuanApi()
this.kernelApi = kernelApi
}

public async preEditPost(post: Post, id?: string, publishCfg?: any): Promise<Post> {
const cfg: BlogConfig = publishCfg.cfg
const dynCfg: DynamicConfig = publishCfg.dynCfg

// const unsupportedPicturePlatform = ["custom_Zhihu","common_notion"],判断key包含zhihu、notion,custom_Zhihu 或者 /custom_Zhihu-\w+/
// PictureStoreTypeEnum.Picgo 先检测是否安装了Picgo插件,如果设置了图片存储方式 PicGO图床 类型就使用 PicGO图床 上传
// PictureStoreTypeEnum.Platform or key in unsupportedPicturePlatform 如果设置了图片存储方式为 平台存储 类型或者 知乎、Notion等不兼容链接方式的平台,就使用 平台特定的存储方式 上传
// PictureStoreTypeEnum.Default 默认不处理,即使用 思源笔记图床 上传

// ==========================
// 使用 PicGO上传图片
// ==========================
// 图片替换
this.logger.debug("开始图片处理, post =>", { post })
post.markdown = await this.picgoBridge.handlePicgo(id, post.markdown)
// 利用 lute 把 md 转换成 html
post.html = LuteUtil.mdToHtml(post.markdown)
this.logger.debug("图片处理完毕, post.markdown =>", { md: post.markdown })

// ==========================
// 使用平台上传图片
// ==========================
// 找到所有的图片
const images = await this.picgoBridge.getImageItemsFromMd(id, post.markdown)
if (images.length === 0) {
this.logger.info("未找到图片,不处理")
return post
// 判断key包含zhihu、notion,custom_Zhihu 或者 /custom_Zhihu-\w+/
const unsupportedPicturePlatform: string[] = ["custom_Zhihu", "custom_Notion"]
const isPicgoInstalled: boolean = await this.checkPicgoInstalled()
if (!isPicgoInstalled) {
this.logger.warn("未安装 PicGO 插件,将使用平台上传图片")
}
// 批量处理图片上传
this.logger.info(`找到${images.length}张图片,开始上传`)
const urlMap = {}
for (const image of images) {
const imageUrl = image.url
const base64Info = await this.readFileToBase64(imageUrl, cfg)
const bits = base64ToBuffer(base64Info.imageBase64)
const mediaObject = new MediaObject(image.name, base64Info.mimeType, bits)
this.logger.debug("before upload, mediaObject =>", mediaObject)
const attachResult = await this.api.newMediaObject(mediaObject)
this.logger.debug("attachResult =>", attachResult)
if (attachResult && attachResult.url) {
urlMap[image.originUrl] = attachResult.url
// 注意如果 platformKey=custom_Zhihu 或者 custom_Zhihu-xxx custom_Notion-xxx 也算 可以参考 /custom_Zhihu-\w+/
const notSupportPictureUrl: boolean = unsupportedPicturePlatform.some((platform) => {
const regex = new RegExp(`${platform}(-\\w+)?`)
return regex.test(dynCfg.platformKey)
})
if (notSupportPictureUrl) {
this.logger.warn("该平台不支持 Picgo 插件,将使用平台上传图片")
}
const usePicgo: boolean = isPicgoInstalled && !notSupportPictureUrl

if (usePicgo) {
// ==========================
// 使用 PicGO上传图片
// ==========================
// 图片替换
this.logger.debug("使用 PicGO上传图片")
this.logger.debug("开始图片处理, post =>", { post })
post.markdown = await this.picgoBridge.handlePicgo(id, post.markdown)
// 利用 lute 把 md 转换成 html
post.html = LuteUtil.mdToHtml(post.markdown)
this.logger.debug("图片处理完毕, post.markdown =>", { md: post.markdown })
} else {
// ==========================
// 使用平台上传图片
// ==========================
this.logger.debug("使用平台上传图片")
// 找到所有的图片
const images = await this.picgoBridge.getImageItemsFromMd(id, post.markdown)
if (images.length === 0) {
this.logger.info("未找到图片,不处理")
return post
}
// 批量处理图片上传
this.logger.info(`找到${images.length}张图片,开始上传`)
const urlMap = {}
for (const image of images) {
const imageUrl = image.url
const base64Info = await this.readFileToBase64(imageUrl, cfg)
const bits = base64ToBuffer(base64Info.imageBase64)
const mediaObject = new MediaObject(image.name, base64Info.mimeType, bits)
this.logger.debug("before upload, mediaObject =>", mediaObject)
const attachResult = await this.api.newMediaObject(mediaObject)
this.logger.debug("attachResult =>", attachResult)
if (attachResult && attachResult.url) {
urlMap[image.originUrl] = attachResult.url
}
}
this.logger.info("平台图片全部上传完成,urlMap =>", urlMap)
}

this.logger.info("图片全部上传完成,urlMap =>", urlMap)
return post
}

// ================
// private methods
// ================
private async checkPicgoInstalled() {
// 检测是否安装 picgo 插件
return await isFileExists(this.kernelApi, "/data/plugins/siyuan-plugin-picgo/plugin.json", "text")
}

private async readFileToBase64(url: string, cfg: BlogConfig): Promise<any> {
let base64Info: any
if (this.isSiyuanOrSiyuanNewWin) {
Expand Down
46 changes: 46 additions & 0 deletions src/utils/siyuanUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023, Terwer . All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Terwer designates this
* particular file as subject to the "Classpath" exception as provided
* by Terwer in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Terwer, Shenzhen, Guangdong, China, youweics@163.com
* or visit www.terwer.space if you need additional information or have any
* questions.
*/

import { SiyuanKernelApi } from "zhi-siyuan-api"
import { StrUtil } from "zhi-common"

/**
* 文件是否存在
*
* @param kernelApi - kernelApi
* @param p - 路径
* @param type - 类型
*/
export const isFileExists = async (kernelApi: SiyuanKernelApi, p: string, type: "text" | "json") => {
try {
const res = await kernelApi.getFile(p, type)
if (type === "text") {
return !StrUtil.isEmptyString(res)
}
return res !== null
} catch {
return false
}
}

0 comments on commit 090425c

Please sign in to comment.