diff --git a/src/adaptors/api/gitlab-vitepress/gitlabvitepressApiAdaptor.ts b/src/adaptors/api/gitlab-vitepress/gitlabvitepressApiAdaptor.ts new file mode 100644 index 00000000..1db00b7e --- /dev/null +++ b/src/adaptors/api/gitlab-vitepress/gitlabvitepressApiAdaptor.ts @@ -0,0 +1,78 @@ +/* + * 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 { BlogConfig, PageTypeEnum, Post, YamlConvertAdaptor } from "zhi-blog-api" +import { GitlabvitepressYamlConverterAdaptor } from "~/src/adaptors/api/gitlab-hexo/gitlabvitepressYamlConverterAdaptor.ts" +import { CommonGitlabApiAdaptor } from "~/src/adaptors/api/base/gitlab/commonGitlabApiAdaptor.ts" +import _ from "lodash" +import {YamlUtil} from "zhi-common"; + +/** + * Gitlabvitepress API 适配器 + * + * @author terwer + * @version 1.3.2 + * @since 0.8.1 + */ +class GitlabvitepressApiAdaptor extends CommonGitlabApiAdaptor { + public override getYamlAdaptor(): YamlConvertAdaptor { + return new GitlabvitepressYamlConverterAdaptor() + } + + public override async preEditPost(post: Post, id?: string, publishCfg?: any): Promise { + // 公共的属性预处理 + const doc = await super.preEditPost(post, id, publishCfg) + + // HEXO 自带的处理 + const cfg: BlogConfig = publishCfg?.cfg + const updatedPost = _.cloneDeep(doc) as Post + + // 自定义处理 + const md = updatedPost.markdown + this.logger.info("准备处理 Gitlabvitepress 正文") + this.logger.debug("md =>", { md: md }) + const yfm = YamlUtil.extractFrontmatter(md, true) + let updatedMd = YamlUtil.extractMarkdown(md) + + // ====== + // 可修改 updatedMd + // ====== + + updatedPost.markdown = `${yfm}\n${updatedMd}` + this.logger.info("Gitlabvitepress 正文处理完毕") + this.logger.debug("updatedMd =>", { yfm: yfm, updatedMd: updatedMd }) + + // 发布格式 + if (cfg?.pageType == PageTypeEnum.Markdown) { + updatedPost.description = updatedPost.markdown + } else { + updatedPost.description = updatedPost.html + } + + return updatedPost + } +} + +export { GitlabvitepressApiAdaptor } diff --git a/src/adaptors/api/gitlab-vitepress/gitlabvitepressConfig.ts b/src/adaptors/api/gitlab-vitepress/gitlabvitepressConfig.ts new file mode 100644 index 00000000..778b3f9c --- /dev/null +++ b/src/adaptors/api/gitlab-vitepress/gitlabvitepressConfig.ts @@ -0,0 +1,69 @@ +/* + * 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 { CategoryTypeEnum, PageTypeEnum, PasswordType } from "zhi-blog-api" +import { VitepressConfig } from "~/src/adaptors/api/vitepress/vitepressConfig.ts" + +/** + * Hexo 配置 + * + * @author terwer + * @since 1.14.0 + */ +class GitlabvitepressConfig extends VitepressConfig { + constructor( + githubUsername: string, + githubAuthToken: string, + githubRepo: string, + githubBranch: string, + middlewareUrl?: string + ) { + super(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + + this.home = "[your-gitlab-home]" + this.apiUrl = "[your-gitlab-api-url]" + this.tokenSettingUrl = "[your-gitlab-host]/-/profile/personal_access_tokens" + this.showTokenTip = true + this.defaultPath = "docs" + this.previewUrl = "/[user]/[repo]/blob/[branch]/[docpath]" + this.previewPostUrl = "/post/[postid].html" + this.mdFilenameRule = "[slug].md" + this.pageType = PageTypeEnum.Markdown + this.passwordType = PasswordType.PasswordType_Token + this.allowPreviewUrlChange = false + this.tagEnabled = true + this.cateEnabled = true + this.allowCateChange = true + this.categoryType = CategoryTypeEnum.CategoryType_Multi + this.knowledgeSpaceEnabled = true + this.allowKnowledgeSpaceChange = false + this.placeholder.knowledgeSpaceReadonlyModeTip = "Gitlabvitepress 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + this.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + this.useMdFilename = false + this.usePathCategory = false + } +} + +export { GitlabvitepressConfig } diff --git a/src/adaptors/api/gitlab-vitepress/gitlabvitepressPlaceHolder.ts b/src/adaptors/api/gitlab-vitepress/gitlabvitepressPlaceHolder.ts new file mode 100644 index 00000000..a51b8d0a --- /dev/null +++ b/src/adaptors/api/gitlab-vitepress/gitlabvitepressPlaceHolder.ts @@ -0,0 +1,30 @@ +/* + * 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 { VitepressPlaceHolder } from "~/src/adaptors/api/vitepress/vitepressPlaceHolder.ts" + +class GitlabvitepressPlaceHolder extends VitepressPlaceHolder {} + +export { GitlabvitepressPlaceHolder } diff --git a/src/adaptors/api/gitlab-vitepress/gitlabvitepressYamlConverterAdaptor.ts b/src/adaptors/api/gitlab-vitepress/gitlabvitepressYamlConverterAdaptor.ts new file mode 100644 index 00000000..a3017a8d --- /dev/null +++ b/src/adaptors/api/gitlab-vitepress/gitlabvitepressYamlConverterAdaptor.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022-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 { VitepressYamlConverterAdaptor } from "~/src/adaptors/api/vitepress/vitepressYamlConverterAdaptor.ts" + +/** + * Vitepress 平台的YAML解析器 + * + * @author terwer + * @since 0.8.1 + */ +class GitlabvitepressYamlConverterAdaptor extends VitepressYamlConverterAdaptor {} + +export { GitlabvitepressYamlConverterAdaptor } diff --git a/src/adaptors/api/gitlab-vitepress/useGitlabvitepressApi.ts b/src/adaptors/api/gitlab-vitepress/useGitlabvitepressApi.ts new file mode 100644 index 00000000..86ad3651 --- /dev/null +++ b/src/adaptors/api/gitlab-vitepress/useGitlabvitepressApi.ts @@ -0,0 +1,112 @@ +/* + * 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 { createAppLogger } from "~/src/utils/appLogger.ts" +import { PublisherAppInstance } from "~/src/publisherAppInstance.ts" +import { useSettingStore } from "~/src/stores/useSettingStore.ts" +import { JsonUtil, ObjectUtil, StrUtil } from "zhi-common" +import { Utils } from "~/src/utils/utils.ts" +import { getDynPostidKey } from "~/src/platforms/dynamicConfig.ts" +import { CategoryTypeEnum } from "zhi-blog-api" +import { GitlabvitepressConfig } from "~/src/adaptors/api/gitlab-vitepress/gitlabvitepressConfig.ts" +import { GitlabvitepressYamlConverterAdaptor } from "~/src/adaptors/api/gitlab-vitepress/gitlabvitepressYamlConverterAdaptor.ts" +import { GitlabvitepressApiAdaptor } from "~/src/adaptors/api/gitlab-vitepress/gitlabvitepressApiAdaptor.ts" + +const useGitlabvitepressApi = async (key: string, newCfg?: GitlabvitepressConfig) => { + // 创建应用日志记录器 + const logger = createAppLogger("use-gitlab-vitepress-api") + + // 记录开始使用 Hexo API + logger.info("Start using Gitlabvitepress API...") + + // 创建应用实例 + const appInstance = new PublisherAppInstance() + + let cfg: GitlabvitepressConfig + if (newCfg) { + logger.info("Initialize with the latest newCfg passed in...") + cfg = newCfg + } else { + // 从配置中获取数据 + const { getSetting } = useSettingStore() + const setting = await getSetting() + cfg = JsonUtil.safeParse(setting[key], {} as GitlabvitepressConfig) + + // 如果配置为空,则使用默认的环境变量值,并记录日志 + if (ObjectUtil.isEmptyObject(cfg)) { + // 从环境变量获取 Hexo API 的 URL、认证令牌和其他配置信息 + const githubUsername = Utils.emptyOrDefault(process.env.VITE_GITLAB_USERNAME, "") + const githubAuthToken = Utils.emptyOrDefault(process.env.VITE_GITLAB_AUTH_TOKEN, "") + const githubRepo = Utils.emptyOrDefault(process.env.VITE_GITLAB_REPO, "") + const githubBranch = Utils.emptyOrDefault(process.env.VITE_GITLAB_BRANCH, "main") + const middlewareUrl = Utils.emptyOrDefault( + process.env.VITE_MIDDLEWARE_URL, + "https://api.terwer.space/api/middleware" + ) + cfg = new GitlabvitepressConfig(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + logger.info("Configuration is empty, using default environment variables.") + } else { + logger.info("Using configuration from settings...") + } + // 初始化posidKey + if (StrUtil.isEmptyString(cfg.posidKey)) { + // 默认值 + cfg.posidKey = getDynPostidKey(key) + } + } + + // 文件规则 + cfg.mdFilenameRule = "[slug].md" + cfg.useMdFilename = false + cfg.usePathCategory = false + // 标签 + cfg.tagEnabled = true + // 分类 + cfg.cateEnabled = true + cfg.allowCateChange = true + cfg.categoryType = CategoryTypeEnum.CategoryType_Multi + // 知识空间 + cfg.knowledgeSpaceEnabled = true + cfg.knowledgeSpaceTitle = "发布目录" + cfg.allowKnowledgeSpaceChange = false + cfg.placeholder.knowledgeSpaceReadonlyModeTip = + "Gitlabvitepress 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + cfg.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + + // 创建 Hexo 的 yamlAdaptor + const yamlAdaptor = new GitlabvitepressYamlConverterAdaptor() + + // 创建 Hexo API 适配器 + const blogApi = new GitlabvitepressApiAdaptor(appInstance, cfg) + logger.info("Gitlabvitepress API created successfully.", cfg) + + return { + cfg, + yamlAdaptor, + blogApi, + } +} + +export { useGitlabvitepressApi } diff --git a/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2ApiAdaptor.ts b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2ApiAdaptor.ts new file mode 100644 index 00000000..4f7785e9 --- /dev/null +++ b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2ApiAdaptor.ts @@ -0,0 +1,78 @@ +/* + * 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 { BlogConfig, PageTypeEnum, Post, YamlConvertAdaptor } from "zhi-blog-api" +import { Gitlabvuepress2YamlConverterAdaptor } from "~/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2YamlConverterAdaptor.ts" +import { CommonGitlabApiAdaptor } from "~/src/adaptors/api/base/gitlab/commonGitlabApiAdaptor.ts" +import _ from "lodash" +import { YamlUtil } from "zhi-common" + +/** + * Gitlabvuepress2 API 适配器 + * + * @author terwer + * @version 1.3.2 + * @since 0.8.1 + */ +class Gitlabvuepress2ApiAdaptor extends CommonGitlabApiAdaptor { + public override getYamlAdaptor(): YamlConvertAdaptor { + return new Gitlabvuepress2YamlConverterAdaptor() + } + + public override async preEditPost(post: Post, id?: string, publishCfg?: any): Promise { + // 公共的属性预处理 + const doc = await super.preEditPost(post, id, publishCfg) + + // HEXO 自带的处理 + const cfg: BlogConfig = publishCfg?.cfg + const updatedPost = _.cloneDeep(doc) as Post + + // 自定义处理 + const md = updatedPost.markdown + this.logger.info("准备处理 Gitlabvuepress2 正文") + this.logger.debug("md =>", { md: md }) + const yfm = YamlUtil.extractFrontmatter(md, true) + let updatedMd = YamlUtil.extractMarkdown(md) + + // ====== + // 可修改 updatedMd + // ====== + + updatedPost.markdown = `${yfm}\n${updatedMd}` + this.logger.info("Gitlabvuepress2 正文处理完毕") + this.logger.debug("updatedMd =>", { yfm: yfm, updatedMd: updatedMd }) + + // 发布格式 + if (cfg?.pageType == PageTypeEnum.Markdown) { + updatedPost.description = updatedPost.markdown + } else { + updatedPost.description = updatedPost.html + } + + return updatedPost + } +} + +export { Gitlabvuepress2ApiAdaptor } diff --git a/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2Config.ts b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2Config.ts new file mode 100644 index 00000000..d832cc27 --- /dev/null +++ b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2Config.ts @@ -0,0 +1,69 @@ +/* + * 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 { CategoryTypeEnum, PageTypeEnum, PasswordType } from "zhi-blog-api" +import { Vuepress2Config } from "~/src/adaptors/api/vuepress2/vuepress2Config.ts" + +/** + * Vuepress2 配置 + * + * @author terwer + * @since 1.14.0 + */ +class Gitlabvuepress2Config extends Vuepress2Config { + constructor( + githubUsername: string, + githubAuthToken: string, + githubRepo: string, + githubBranch: string, + middlewareUrl?: string + ) { + super(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + + this.home = "[your-gitlab-home]" + this.apiUrl = "[your-gitlab-api-url]" + this.tokenSettingUrl = "[your-gitlab-host]/-/profile/personal_access_tokens" + this.showTokenTip = true + this.defaultPath = "src/post" + this.previewUrl = "/[user]/[repo]/blob/[branch]/[docpath]" + this.previewPostUrl = "/post/[postid].html" + this.mdFilenameRule = "[slug].md" + this.pageType = PageTypeEnum.Markdown + this.passwordType = PasswordType.PasswordType_Token + this.allowPreviewUrlChange = false + this.tagEnabled = true + this.cateEnabled = true + this.allowCateChange = true + this.categoryType = CategoryTypeEnum.CategoryType_Multi + this.knowledgeSpaceEnabled = true + this.allowKnowledgeSpaceChange = false + this.placeholder.knowledgeSpaceReadonlyModeTip = "Gitlabvuepress2 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + this.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + this.useMdFilename = false + this.usePathCategory = false + } +} + +export { Gitlabvuepress2Config } diff --git a/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2PlaceHolder.ts b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2PlaceHolder.ts new file mode 100644 index 00000000..0a202387 --- /dev/null +++ b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2PlaceHolder.ts @@ -0,0 +1,30 @@ +/* + * 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 { Vuepress2PlaceHolder } from "~/src/adaptors/api/vuepress2/vuepress2PlaceHolder.ts" + +class Gitlabvuepress2PlaceHolder extends Vuepress2PlaceHolder {} + +export { Gitlabvuepress2PlaceHolder } diff --git a/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2YamlConverterAdaptor.ts b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2YamlConverterAdaptor.ts new file mode 100644 index 00000000..cd995810 --- /dev/null +++ b/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2YamlConverterAdaptor.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022-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 { Vuepress2YamlConverterAdaptor } from "~/src/adaptors/api/vuepress2/vuepress2YamlConverterAdaptor.ts" + +/** + * Vuepress2 平台的YAML解析器 + * + * @author terwer + * @since 0.8.1 + */ +class Gitlabvuepress2YamlConverterAdaptor extends Vuepress2YamlConverterAdaptor {} + +export { Gitlabvuepress2YamlConverterAdaptor } diff --git a/src/adaptors/api/gitlab-vuepress2/useGitlabvuepress2Api.ts b/src/adaptors/api/gitlab-vuepress2/useGitlabvuepress2Api.ts new file mode 100644 index 00000000..48f66105 --- /dev/null +++ b/src/adaptors/api/gitlab-vuepress2/useGitlabvuepress2Api.ts @@ -0,0 +1,112 @@ +/* + * 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 { createAppLogger } from "~/src/utils/appLogger.ts" +import { PublisherAppInstance } from "~/src/publisherAppInstance.ts" +import { useSettingStore } from "~/src/stores/useSettingStore.ts" +import { JsonUtil, ObjectUtil, StrUtil } from "zhi-common" +import { Utils } from "~/src/utils/utils.ts" +import { getDynPostidKey } from "~/src/platforms/dynamicConfig.ts" +import { CategoryTypeEnum } from "zhi-blog-api" +import { Gitlabvuepress2Config } from "~/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2Config.ts" +import { Gitlabvuepress2YamlConverterAdaptor } from "~/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2YamlConverterAdaptor.ts" +import { Gitlabvuepress2ApiAdaptor } from "~/src/adaptors/api/gitlab-vuepress2/gitlabvuepress2ApiAdaptor.ts" + +const useGitlabvuepress2Api = async (key: string, newCfg?: Gitlabvuepress2Config) => { + // 创建应用日志记录器 + const logger = createAppLogger("use-gitlab-hexo-api") + + // 记录开始使用 Hexo API + logger.info("Start using Gitlabvuepress2 API...") + + // 创建应用实例 + const appInstance = new PublisherAppInstance() + + let cfg: Gitlabvuepress2Config + if (newCfg) { + logger.info("Initialize with the latest newCfg passed in...") + cfg = newCfg + } else { + // 从配置中获取数据 + const { getSetting } = useSettingStore() + const setting = await getSetting() + cfg = JsonUtil.safeParse(setting[key], {} as Gitlabvuepress2Config) + + // 如果配置为空,则使用默认的环境变量值,并记录日志 + if (ObjectUtil.isEmptyObject(cfg)) { + // 从环境变量获取 Hexo API 的 URL、认证令牌和其他配置信息 + const githubUsername = Utils.emptyOrDefault(process.env.VITE_GITLAB_USERNAME, "") + const githubAuthToken = Utils.emptyOrDefault(process.env.VITE_GITLAB_AUTH_TOKEN, "") + const githubRepo = Utils.emptyOrDefault(process.env.VITE_GITLAB_REPO, "") + const githubBranch = Utils.emptyOrDefault(process.env.VITE_GITLAB_BRANCH, "main") + const middlewareUrl = Utils.emptyOrDefault( + process.env.VITE_MIDDLEWARE_URL, + "https://api.terwer.space/api/middleware" + ) + cfg = new Gitlabvuepress2Config(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + logger.info("Configuration is empty, using default environment variables.") + } else { + logger.info("Using configuration from settings...") + } + // 初始化posidKey + if (StrUtil.isEmptyString(cfg.posidKey)) { + // 默认值 + cfg.posidKey = getDynPostidKey(key) + } + } + + // 文件规则 + cfg.mdFilenameRule = "[slug].md" + cfg.useMdFilename = false + cfg.usePathCategory = false + // 标签 + cfg.tagEnabled = true + // 分类 + cfg.cateEnabled = true + cfg.allowCateChange = true + cfg.categoryType = CategoryTypeEnum.CategoryType_Multi + // 知识空间 + cfg.knowledgeSpaceEnabled = true + cfg.knowledgeSpaceTitle = "发布目录" + cfg.allowKnowledgeSpaceChange = false + cfg.placeholder.knowledgeSpaceReadonlyModeTip = + "Gitlabvuepress2 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + cfg.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + + // 创建 Hexo 的 yamlAdaptor + const yamlAdaptor = new Gitlabvuepress2YamlConverterAdaptor() + + // 创建 Hexo API 适配器 + const blogApi = new Gitlabvuepress2ApiAdaptor(appInstance, cfg) + logger.info("Gitlabvuepress2 API created successfully.", cfg) + + return { + cfg, + yamlAdaptor, + blogApi, + } +} + +export { useGitlabvuepress2Api } diff --git a/src/adaptors/api/vitepress/useVitepressApi.ts b/src/adaptors/api/vitepress/useVitepressApi.ts new file mode 100644 index 00000000..60d23f21 --- /dev/null +++ b/src/adaptors/api/vitepress/useVitepressApi.ts @@ -0,0 +1,111 @@ +/* + * 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 { createAppLogger } from "~/src/utils/appLogger.ts" +import { PublisherAppInstance } from "~/src/publisherAppInstance.ts" +import { useSettingStore } from "~/src/stores/useSettingStore.ts" +import { JsonUtil, ObjectUtil, StrUtil } from "zhi-common" +import { Utils } from "~/src/utils/utils.ts" +import { getDynPostidKey } from "~/src/platforms/dynamicConfig.ts" +import { VitepressConfig } from "~/src/adaptors/api/vitepress/vitepressConfig.ts" +import { VitepressApiAdaptor } from "~/src/adaptors/api/vitepress/vitepressApiAdaptor.ts" +import { VitepressYamlConverterAdaptor } from "~/src/adaptors/api/vitepress/vitepressYamlConverterAdaptor.ts" +import { CategoryTypeEnum } from "zhi-blog-api" + +const useVitepressApi = async (key: string, newCfg?: VitepressConfig) => { + // 创建应用日志记录器 + const logger = createAppLogger("use-vitepress-api") + + // 记录开始使用 Vitepress API + logger.info("Start using Vitepress API...") + + // 创建应用实例 + const appInstance = new PublisherAppInstance() + + let cfg: VitepressConfig + if (newCfg) { + logger.info("Initialize with the latest newCfg passed in...") + cfg = newCfg + } else { + // 从配置中获取数据 + const { getSetting } = useSettingStore() + const setting = await getSetting() + cfg = JsonUtil.safeParse(setting[key], {} as VitepressConfig) + + // 如果配置为空,则使用默认的环境变量值,并记录日志 + if (ObjectUtil.isEmptyObject(cfg)) { + // 从环境变量获取 Vitepress API 的 URL、认证令牌和其他配置信息 + const githubUsername = Utils.emptyOrDefault(process.env.VITE_GITHUB_USERNAME, "") + const githubAuthToken = Utils.emptyOrDefault(process.env.VITE_GITHUB_AUTH_TOKEN, "") + const githubRepo = Utils.emptyOrDefault(process.env.VITE_GITHUB_REPO, "") + const githubBranch = Utils.emptyOrDefault(process.env.VITE_GITHUB_BRANCH, "main") + const middlewareUrl = Utils.emptyOrDefault( + process.env.VITE_MIDDLEWARE_URL, + "https://api.terwer.space/api/middleware" + ) + cfg = new VitepressConfig(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + logger.info("Configuration is empty, using default environment variables.") + } else { + logger.info("Using configuration from settings...") + } + // 初始化posidKey + if (StrUtil.isEmptyString(cfg.posidKey)) { + // 默认值 + cfg.posidKey = getDynPostidKey(key) + } + } + + // 文件规则,占位符 + cfg.mdFilenameRule = "[slug].md" + cfg.useMdFilename = false + cfg.usePathCategory = false + // 标签 + cfg.tagEnabled = true + // 分类 + cfg.cateEnabled = true + cfg.allowCateChange = true + cfg.categoryType = CategoryTypeEnum.CategoryType_Multi + // 知识空间 + cfg.knowledgeSpaceEnabled = true + cfg.knowledgeSpaceTitle = "发布目录" + cfg.allowKnowledgeSpaceChange = false + cfg.placeholder.knowledgeSpaceReadonlyModeTip = "Vitepress 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + cfg.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + + // 创建 Vitepress 的 yamlAdaptor + const yamlAdaptor = new VitepressYamlConverterAdaptor() + + // 创建 Vitepress API 适配器 + const blogApi = new VitepressApiAdaptor(appInstance, cfg) + logger.info("Vitepress API created successfully.", cfg) + + return { + cfg, + yamlAdaptor, + blogApi, + } +} + +export { useVitepressApi } diff --git a/src/adaptors/api/vitepress/vitepressApiAdaptor.ts b/src/adaptors/api/vitepress/vitepressApiAdaptor.ts new file mode 100644 index 00000000..30ae332b --- /dev/null +++ b/src/adaptors/api/vitepress/vitepressApiAdaptor.ts @@ -0,0 +1,78 @@ +/* + * 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 { CommonGithubApiAdaptor } from "~/src/adaptors/api/base/github/commonGithubApiAdaptor.ts" +import { BlogConfig, PageTypeEnum, Post, YamlConvertAdaptor } from "zhi-blog-api" +import { VitepressYamlConverterAdaptor } from "~/src/adaptors/api/vitepress/vitepressYamlConverterAdaptor.ts" +import _ from "lodash" +import { YamlUtil } from "zhi-common" + +/** + * Vitepress API 适配器 + * + * @author terwer + * @version 1.3.2 + * @since 0.8.1 + */ +class VitepressApiAdaptor extends CommonGithubApiAdaptor { + public override getYamlAdaptor(): YamlConvertAdaptor { + return new VitepressYamlConverterAdaptor() + } + + public override async preEditPost(post: Post, id?: string, publishCfg?: any): Promise { + // 公共的属性预处理 + const doc = await super.preEditPost(post, id, publishCfg) + + // HEXO 自带的处理 + const cfg: BlogConfig = publishCfg?.cfg + const updatedPost = _.cloneDeep(doc) as Post + + // 自定义处理 + const md = updatedPost.markdown + this.logger.info("准备处理 Vitepress 正文") + this.logger.debug("md =>", { md: md }) + const yfm = YamlUtil.extractFrontmatter(md, true) + let updatedMd = YamlUtil.extractMarkdown(md) + + // ====== + // 可修改 updatedMd + // ====== + + updatedPost.markdown = `${yfm}\n${updatedMd}` + this.logger.info("Vitepress 正文处理完毕") + this.logger.debug("updatedMd =>", { yfm: yfm, updatedMd: updatedMd }) + + // 发布格式 + if (cfg?.pageType == PageTypeEnum.Markdown) { + updatedPost.description = updatedPost.markdown + } else { + updatedPost.description = updatedPost.html + } + + return updatedPost + } +} + +export { VitepressApiAdaptor } diff --git a/src/adaptors/api/vitepress/vitepressConfig.ts b/src/adaptors/api/vitepress/vitepressConfig.ts new file mode 100644 index 00000000..802ab311 --- /dev/null +++ b/src/adaptors/api/vitepress/vitepressConfig.ts @@ -0,0 +1,67 @@ +/* + * 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 { CommonGithubConfig } from "~/src/adaptors/api/base/github/commonGithubConfig.ts" +import { CategoryTypeEnum, PageTypeEnum, PasswordType } from "zhi-blog-api" + +/** + * Vitepress 配置 + * + * @author terwer + * @since 1.3.2 + */ +class VitepressConfig extends CommonGithubConfig { + constructor( + githubUsername: string, + githubAuthToken: string, + githubRepo: string, + githubBranch: string, + middlewareUrl?: string + ) { + super(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + + this.tokenSettingUrl = "https://github.com/settings/tokens" + this.showTokenTip = true + this.defaultPath = "docs" + this.previewUrl = "/[user]/[repo]/blob/[branch]/[docpath]" + this.previewPostUrl = "/post/[postid].html" + this.mdFilenameRule = "[slug].md" + this.pageType = PageTypeEnum.Markdown + this.passwordType = PasswordType.PasswordType_Token + this.allowPreviewUrlChange = false + this.tagEnabled = true + this.cateEnabled = true + this.allowCateChange = true + this.categoryType = CategoryTypeEnum.CategoryType_Multi + this.knowledgeSpaceEnabled = true + this.allowKnowledgeSpaceChange = false + this.placeholder.knowledgeSpaceReadonlyModeTip = "Vitepress 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + this.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + this.useMdFilename = false + this.usePathCategory = false + } +} + +export { VitepressConfig } diff --git a/src/adaptors/api/vitepress/vitepressPlaceHolder.ts b/src/adaptors/api/vitepress/vitepressPlaceHolder.ts new file mode 100644 index 00000000..e07458de --- /dev/null +++ b/src/adaptors/api/vitepress/vitepressPlaceHolder.ts @@ -0,0 +1,30 @@ +/* + * 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 { CommonGithubPlaceholder } from "~/src/adaptors/api/base/github/commonGithubPlaceholder.ts" + +class VitepressPlaceHolder extends CommonGithubPlaceholder {} + +export { VitepressPlaceHolder } diff --git a/src/adaptors/api/vitepress/vitepressYamlConverterAdaptor.ts b/src/adaptors/api/vitepress/vitepressYamlConverterAdaptor.ts new file mode 100644 index 00000000..62cbe65b --- /dev/null +++ b/src/adaptors/api/vitepress/vitepressYamlConverterAdaptor.ts @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2022-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 { createAppLogger } from "~/src/utils/appLogger.ts" +import { BlogConfig, Post, YamlConvertAdaptor, YamlFormatObj } from "zhi-blog-api" +import { DateUtil, StrUtil, YamlUtil } from "zhi-common" +import { CommonGithubConfig } from "~/src/adaptors/api/base/github/commonGithubConfig.ts" +import { toRaw } from "vue" + +/** + * Vitepress 平台的YAML解析器 + * + * @see {https://vitepress.io/docs/front-matter front-tmatter} + * @author terwer + * @since 0.8.1 + */ +class VitepressYamlConverterAdaptor extends YamlConvertAdaptor { + private readonly logger = createAppLogger("vitepress-yaml-converter-adaptor") + + public convertToYaml(post: Post, cfg?: BlogConfig): YamlFormatObj { + this.logger.debug("您正在使用 Vitepress Yaml Converter", { post: toRaw(post) }) + let yamlFormatObj: YamlFormatObj = new YamlFormatObj() + // title + yamlFormatObj.yamlObj.title = post.title + + // date + yamlFormatObj.yamlObj.date = DateUtil.formatIsoToZh(post.dateCreated.toISOString(), true) + + // updated + if (!post.dateUpdated) { + post.dateUpdated = new Date() + } + yamlFormatObj.yamlObj.updated = DateUtil.formatIsoToZh(post.dateUpdated.toISOString(), true) + + // excerpt + if (!StrUtil.isEmptyString(post.shortDesc)) { + yamlFormatObj.yamlObj.excerpt = post.shortDesc + } + + // tags + if (!StrUtil.isEmptyString(post.mt_keywords)) { + const tags = post.mt_keywords.split(",") + yamlFormatObj.yamlObj.tags = tags + } + + // categories + if (post.categories?.length > 0) { + yamlFormatObj.yamlObj.categories = post.categories + } + + // permalink + if (cfg.yamlLinkEnabled) { + let link = "/post/" + post.wp_slug + ".html" + if (cfg instanceof CommonGithubConfig) { + const githubCfg = cfg as CommonGithubConfig + if (!StrUtil.isEmptyString(cfg.previewPostUrl)) { + link = githubCfg.previewPostUrl.replace("[postid]", post.wp_slug) + const created = DateUtil.formatIsoToZh(post.dateCreated.toISOString(), true) + const datearr = created.split(" ")[0] + const numarr = datearr.split("-") + this.logger.debug("created numarr=>", numarr) + const y = numarr[0] + const m = numarr[1] + const d = numarr[2] + link = link.replace(/\[yyyy]/g, y) + link = link.replace(/\[MM]/g, m) + link = link.replace(/\[mm]/g, m) + link = link.replace(/\[dd]/g, d) + + if (yamlFormatObj.yamlObj.categories?.length > 0) { + link = link.replace(/\[cats]/, yamlFormatObj.yamlObj.categories.join("/")) + } else { + link = link.replace(/\/\[cats]/, "") + } + } + } + yamlFormatObj.yamlObj.permalink = link + } + + // comments + yamlFormatObj.yamlObj.comments = true + + // toc + yamlFormatObj.yamlObj.toc = true + + // formatter + let yaml = YamlUtil.obj2Yaml(yamlFormatObj.yamlObj) + this.logger.debug("yaml=>", yaml) + + yamlFormatObj.formatter = yaml + yamlFormatObj.mdContent = post.markdown + yamlFormatObj.mdFullContent = YamlUtil.addYamlToMd(yamlFormatObj.formatter, yamlFormatObj.mdContent) + yamlFormatObj.htmlContent = post.html + this.logger.info("生成默认的YAML") + + return yamlFormatObj + } + + public convertToAttr(post: Post, yamlFormatObj: YamlFormatObj, cfg?: BlogConfig): Post { + this.logger.debug("开始转换YAML到Post", yamlFormatObj) + + // 标题 + if (yamlFormatObj.yamlObj?.title) { + post.title = yamlFormatObj.yamlObj?.title + } + + // 发布时间 + if (yamlFormatObj.yamlObj?.date) { + post.dateCreated = DateUtil.convertStringToDate(yamlFormatObj.yamlObj?.date) + } + if (yamlFormatObj.yamlObj?.updated) { + post.dateUpdated = DateUtil.convertStringToDate(yamlFormatObj.yamlObj?.updated) + } + + // 摘要 + post.shortDesc = yamlFormatObj.yamlObj?.excerpt + + // 标签 + post.mt_keywords = yamlFormatObj.yamlObj?.tags?.join(",") + + // 分类 + post.categories = yamlFormatObj.yamlObj?.categories + + // 添加新的YAML + post.yaml = YamlUtil.obj2Yaml(yamlFormatObj.yamlObj) + + this.logger.debug("转换完成,post =>", post) + return post + } +} + +export { VitepressYamlConverterAdaptor } diff --git a/src/adaptors/api/vuepress2/useVuepress2Api.ts b/src/adaptors/api/vuepress2/useVuepress2Api.ts new file mode 100644 index 00000000..7fd73754 --- /dev/null +++ b/src/adaptors/api/vuepress2/useVuepress2Api.ts @@ -0,0 +1,111 @@ +/* + * 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 { createAppLogger } from "~/src/utils/appLogger.ts" +import { PublisherAppInstance } from "~/src/publisherAppInstance.ts" +import { useSettingStore } from "~/src/stores/useSettingStore.ts" +import { JsonUtil, ObjectUtil, StrUtil } from "zhi-common" +import { Utils } from "~/src/utils/utils.ts" +import { getDynPostidKey } from "~/src/platforms/dynamicConfig.ts" +import { Vuepress2Config } from "~/src/adaptors/api/vuepress2/vuepress2Config.ts" +import { Vuepress2ApiAdaptor } from "~/src/adaptors/api/vuepress2/vuepress2ApiAdaptor.ts" +import { Vuepress2YamlConverterAdaptor } from "~/src/adaptors/api/vuepress2/vuepress2YamlConverterAdaptor.ts" +import { CategoryTypeEnum } from "zhi-blog-api" + +const useVuepress2Api = async (key: string, newCfg?: Vuepress2Config) => { + // 创建应用日志记录器 + const logger = createAppLogger("use-vuepress2-api") + + // 记录开始使用 Vuepress2 API + logger.info("Start using Vuepress2 API...") + + // 创建应用实例 + const appInstance = new PublisherAppInstance() + + let cfg: Vuepress2Config + if (newCfg) { + logger.info("Initialize with the latest newCfg passed in...") + cfg = newCfg + } else { + // 从配置中获取数据 + const { getSetting } = useSettingStore() + const setting = await getSetting() + cfg = JsonUtil.safeParse(setting[key], {} as Vuepress2Config) + + // 如果配置为空,则使用默认的环境变量值,并记录日志 + if (ObjectUtil.isEmptyObject(cfg)) { + // 从环境变量获取 Vuepress2 API 的 URL、认证令牌和其他配置信息 + const githubUsername = Utils.emptyOrDefault(process.env.VITE_GITHUB_USERNAME, "") + const githubAuthToken = Utils.emptyOrDefault(process.env.VITE_GITHUB_AUTH_TOKEN, "") + const githubRepo = Utils.emptyOrDefault(process.env.VITE_GITHUB_REPO, "") + const githubBranch = Utils.emptyOrDefault(process.env.VITE_GITHUB_BRANCH, "main") + const middlewareUrl = Utils.emptyOrDefault( + process.env.VITE_MIDDLEWARE_URL, + "https://api.terwer.space/api/middleware" + ) + cfg = new Vuepress2Config(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + logger.info("Configuration is empty, using default environment variables.") + } else { + logger.info("Using configuration from settings...") + } + // 初始化posidKey + if (StrUtil.isEmptyString(cfg.posidKey)) { + // 默认值 + cfg.posidKey = getDynPostidKey(key) + } + } + + // 文件规则,占位符 + cfg.mdFilenameRule = "[slug].md" + cfg.useMdFilename = false + cfg.usePathCategory = false + // 标签 + cfg.tagEnabled = true + // 分类 + cfg.cateEnabled = true + cfg.allowCateChange = true + cfg.categoryType = CategoryTypeEnum.CategoryType_Multi + // 知识空间 + cfg.knowledgeSpaceEnabled = true + cfg.knowledgeSpaceTitle = "发布目录" + cfg.allowKnowledgeSpaceChange = false + cfg.placeholder.knowledgeSpaceReadonlyModeTip = "Vuepress2 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + cfg.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + + // 创建 Vuepress2 的 yamlAdaptor + const yamlAdaptor = new Vuepress2YamlConverterAdaptor() + + // 创建 Vuepress2 API 适配器 + const blogApi = new Vuepress2ApiAdaptor(appInstance, cfg) + logger.info("Vuepress2 API created successfully.", cfg) + + return { + cfg, + yamlAdaptor, + blogApi, + } +} + +export { useVuepress2Api } diff --git a/src/adaptors/api/vuepress2/vuepress2ApiAdaptor.ts b/src/adaptors/api/vuepress2/vuepress2ApiAdaptor.ts new file mode 100644 index 00000000..ff933ad6 --- /dev/null +++ b/src/adaptors/api/vuepress2/vuepress2ApiAdaptor.ts @@ -0,0 +1,78 @@ +/* + * 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 { CommonGithubApiAdaptor } from "~/src/adaptors/api/base/github/commonGithubApiAdaptor.ts" +import { BlogConfig, PageTypeEnum, Post, YamlConvertAdaptor } from "zhi-blog-api" +import { Vuepress2YamlConverterAdaptor } from "~/src/adaptors/api/vuepress2/vuepress2YamlConverterAdaptor.ts" +import _ from "lodash" +import { YamlUtil } from "zhi-common" + +/** + * Vuepress2 API 适配器 + * + * @author terwer + * @version 1.3.2 + * @since 0.8.1 + */ +class Vuepress2ApiAdaptor extends CommonGithubApiAdaptor { + public override getYamlAdaptor(): YamlConvertAdaptor { + return new Vuepress2YamlConverterAdaptor() + } + + public override async preEditPost(post: Post, id?: string, publishCfg?: any): Promise { + // 公共的属性预处理 + const doc = await super.preEditPost(post, id, publishCfg) + + // HEXO 自带的处理 + const cfg: BlogConfig = publishCfg?.cfg + const updatedPost = _.cloneDeep(doc) as Post + + // 自定义处理 + const md = updatedPost.markdown + this.logger.info("准备处理 Vuepress2 正文") + this.logger.debug("md =>", { md: md }) + const yfm = YamlUtil.extractFrontmatter(md, true) + let updatedMd = YamlUtil.extractMarkdown(md) + + // ====== + // 可修改 updatedMd + // ====== + + updatedPost.markdown = `${yfm}\n${updatedMd}` + this.logger.info("Vuepress2 正文处理完毕") + this.logger.debug("updatedMd =>", { yfm: yfm, updatedMd: updatedMd }) + + // 发布格式 + if (cfg?.pageType == PageTypeEnum.Markdown) { + updatedPost.description = updatedPost.markdown + } else { + updatedPost.description = updatedPost.html + } + + return updatedPost + } +} + +export { Vuepress2ApiAdaptor } diff --git a/src/adaptors/api/vuepress2/vuepress2Config.ts b/src/adaptors/api/vuepress2/vuepress2Config.ts new file mode 100644 index 00000000..b84db2f7 --- /dev/null +++ b/src/adaptors/api/vuepress2/vuepress2Config.ts @@ -0,0 +1,67 @@ +/* + * 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 { CommonGithubConfig } from "~/src/adaptors/api/base/github/commonGithubConfig.ts" +import { CategoryTypeEnum, PageTypeEnum, PasswordType } from "zhi-blog-api" + +/** + * Vuepress2 配置 + * + * @author terwer + * @since 1.3.2 + */ +class Vuepress2Config extends CommonGithubConfig { + constructor( + githubUsername: string, + githubAuthToken: string, + githubRepo: string, + githubBranch: string, + middlewareUrl?: string + ) { + super(githubUsername, githubAuthToken, githubRepo, githubBranch, middlewareUrl) + + this.tokenSettingUrl = "https://github.com/settings/tokens" + this.showTokenTip = true + this.defaultPath = "src/post" + this.previewUrl = "/[user]/[repo]/blob/[branch]/[docpath]" + this.previewPostUrl = "/post/[postid].html" + this.mdFilenameRule = "[slug].md" + this.pageType = PageTypeEnum.Markdown + this.passwordType = PasswordType.PasswordType_Token + this.allowPreviewUrlChange = false + this.tagEnabled = true + this.cateEnabled = true + this.allowCateChange = true + this.categoryType = CategoryTypeEnum.CategoryType_Multi + this.knowledgeSpaceEnabled = true + this.allowKnowledgeSpaceChange = false + this.placeholder.knowledgeSpaceReadonlyModeTip = "Vuepress2 平台暂不支持修改发布目录,如需修改,请删除之后重新发布" + this.knowledgeSpaceType = CategoryTypeEnum.CategoryType_Tree_Single + this.useMdFilename = false + this.usePathCategory = false + } +} + +export { Vuepress2Config } diff --git a/src/adaptors/api/vuepress2/vuepress2PlaceHolder.ts b/src/adaptors/api/vuepress2/vuepress2PlaceHolder.ts new file mode 100644 index 00000000..0d754789 --- /dev/null +++ b/src/adaptors/api/vuepress2/vuepress2PlaceHolder.ts @@ -0,0 +1,30 @@ +/* + * 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 { CommonGithubPlaceholder } from "~/src/adaptors/api/base/github/commonGithubPlaceholder.ts" + +class Vuepress2PlaceHolder extends CommonGithubPlaceholder {} + +export { Vuepress2PlaceHolder } diff --git a/src/adaptors/api/vuepress2/vuepress2YamlConverterAdaptor.ts b/src/adaptors/api/vuepress2/vuepress2YamlConverterAdaptor.ts new file mode 100644 index 00000000..f2515225 --- /dev/null +++ b/src/adaptors/api/vuepress2/vuepress2YamlConverterAdaptor.ts @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2022-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 { createAppLogger } from "~/src/utils/appLogger.ts" +import { BlogConfig, Post, YamlConvertAdaptor, YamlFormatObj } from "zhi-blog-api" +import { DateUtil, StrUtil, YamlUtil } from "zhi-common" +import { CommonGithubConfig } from "~/src/adaptors/api/base/github/commonGithubConfig.ts" +import { toRaw } from "vue" + +/** + * Vuepress2 平台的YAML解析器 + * + * @see {https://vuepress2.io/docs/front-matter front-tmatter} + * @author terwer + * @since 0.8.1 + */ +class Vuepress2YamlConverterAdaptor extends YamlConvertAdaptor { + private readonly logger = createAppLogger("vuepress2-yaml-converter-adaptor") + + public convertToYaml(post: Post, cfg?: BlogConfig): YamlFormatObj { + this.logger.debug("您正在使用 Vuepress2 Yaml Converter", { post: toRaw(post) }) + let yamlFormatObj: YamlFormatObj = new YamlFormatObj() + // title + yamlFormatObj.yamlObj.title = post.title + + // date + yamlFormatObj.yamlObj.date = DateUtil.formatIsoToZh(post.dateCreated.toISOString(), true) + + // updated + if (!post.dateUpdated) { + post.dateUpdated = new Date() + } + yamlFormatObj.yamlObj.updated = DateUtil.formatIsoToZh(post.dateUpdated.toISOString(), true) + + // excerpt + if (!StrUtil.isEmptyString(post.shortDesc)) { + yamlFormatObj.yamlObj.excerpt = post.shortDesc + } + + // tags + if (!StrUtil.isEmptyString(post.mt_keywords)) { + const tags = post.mt_keywords.split(",") + yamlFormatObj.yamlObj.tags = tags + } + + // categories + if (post.categories?.length > 0) { + yamlFormatObj.yamlObj.categories = post.categories + } + + // permalink + if (cfg.yamlLinkEnabled) { + let link = "/post/" + post.wp_slug + ".html" + if (cfg instanceof CommonGithubConfig) { + const githubCfg = cfg as CommonGithubConfig + if (!StrUtil.isEmptyString(cfg.previewPostUrl)) { + link = githubCfg.previewPostUrl.replace("[postid]", post.wp_slug) + const created = DateUtil.formatIsoToZh(post.dateCreated.toISOString(), true) + const datearr = created.split(" ")[0] + const numarr = datearr.split("-") + this.logger.debug("created numarr=>", numarr) + const y = numarr[0] + const m = numarr[1] + const d = numarr[2] + link = link.replace(/\[yyyy]/g, y) + link = link.replace(/\[MM]/g, m) + link = link.replace(/\[mm]/g, m) + link = link.replace(/\[dd]/g, d) + + if (yamlFormatObj.yamlObj.categories?.length > 0) { + link = link.replace(/\[cats]/, yamlFormatObj.yamlObj.categories.join("/")) + } else { + link = link.replace(/\/\[cats]/, "") + } + } + } + yamlFormatObj.yamlObj.permalink = link + } + + // comments + yamlFormatObj.yamlObj.comments = true + + // toc + yamlFormatObj.yamlObj.toc = true + + // formatter + let yaml = YamlUtil.obj2Yaml(yamlFormatObj.yamlObj) + this.logger.debug("yaml=>", yaml) + + yamlFormatObj.formatter = yaml + yamlFormatObj.mdContent = post.markdown + yamlFormatObj.mdFullContent = YamlUtil.addYamlToMd(yamlFormatObj.formatter, yamlFormatObj.mdContent) + yamlFormatObj.htmlContent = post.html + this.logger.info("生成默认的YAML") + + return yamlFormatObj + } + + public convertToAttr(post: Post, yamlFormatObj: YamlFormatObj, cfg?: BlogConfig): Post { + this.logger.debug("开始转换YAML到Post", yamlFormatObj) + + // 标题 + if (yamlFormatObj.yamlObj?.title) { + post.title = yamlFormatObj.yamlObj?.title + } + + // 发布时间 + if (yamlFormatObj.yamlObj?.date) { + post.dateCreated = DateUtil.convertStringToDate(yamlFormatObj.yamlObj?.date) + } + if (yamlFormatObj.yamlObj?.updated) { + post.dateUpdated = DateUtil.convertStringToDate(yamlFormatObj.yamlObj?.updated) + } + + // 摘要 + post.shortDesc = yamlFormatObj.yamlObj?.excerpt + + // 标签 + post.mt_keywords = yamlFormatObj.yamlObj?.tags?.join(",") + + // 分类 + post.categories = yamlFormatObj.yamlObj?.categories + + // 添加新的YAML + post.yaml = YamlUtil.obj2Yaml(yamlFormatObj.yamlObj) + + this.logger.debug("转换完成,post =>", post) + return post + } +} + +export { Vuepress2YamlConverterAdaptor }