diff --git a/astro.config.mjs b/astro.config.mjs index 461e82e..4d748f9 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -17,6 +17,7 @@ import { export default defineConfig({ site: "https://oriverk.dev", publicDir: "./public", + // add data-astro-prefetch to anchor element prefetch: true, integrations: [ svelte(), diff --git a/package-lock.json b/package-lock.json index 3bd2ada..3759600 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,13 +20,16 @@ "clsx": "^2.1.0", "date-fns": "^3.6.0", "dotenv": "^16.4.5", + "gray-matter": "^4.0.3", "hast": "^1.0.0", "mdast": "^3.0.0", "rehype-katex": "^7.0.0", + "remark": "^15.0.1", "remark-comment": "^1.0.0", "remark-github-alerts": "^0.1.0-beta.3", "remark-math": "^6.0.0", "rss-parser": "^3.13.0", + "strip-markdown": "^6.0.0", "svelte": "^4.2.12", "unified": "^11.0.4", "unist-util-inspect": "^8.0.0", @@ -15162,6 +15165,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", + "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-comment": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/remark-comment/-/remark-comment-1.0.0.tgz", @@ -16818,6 +16836,18 @@ "node": ">=0.10.0" } }, + "node_modules/strip-markdown": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-markdown/-/strip-markdown-6.0.0.tgz", + "integrity": "sha512-mSa8FtUoX3ExJYDkjPUTC14xaBAn4Ik5GPQD45G5E2egAmeV3kHgVSTfIoSDggbF6Pk9stahVgqsLCNExv6jHw==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", diff --git a/package.json b/package.json index 150a01c..00bccc5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "script:feed": "node script/getFeed.mjs", "script:github": "node -r dotenv/config script/getGitHubUserContent.mjs", "script:cv": "node -r dotenv/config script/getGitHubRepositoryContent.mjs", + "algolia": "node -r dotenv/config script/algolia.mjs", "astro": "astro", "sync": "astro sync", "dev": "astro dev", @@ -50,13 +51,16 @@ "clsx": "^2.1.0", "date-fns": "^3.6.0", "dotenv": "^16.4.5", + "gray-matter": "^4.0.3", "hast": "^1.0.0", "mdast": "^3.0.0", "rehype-katex": "^7.0.0", + "remark": "^15.0.1", "remark-comment": "^1.0.0", "remark-github-alerts": "^0.1.0-beta.3", "remark-math": "^6.0.0", "rss-parser": "^3.13.0", + "strip-markdown": "^6.0.0", "svelte": "^4.2.12", "unified": "^11.0.4", "unist-util-inspect": "^8.0.0", diff --git a/script/algolia.mjs b/script/algolia.mjs new file mode 100644 index 0000000..c8139a0 --- /dev/null +++ b/script/algolia.mjs @@ -0,0 +1,103 @@ +import path from "path" +import fs from "fs-extra"; +import { remark } from "remark"; +import strip from "strip-markdown"; +import matter from "gray-matter"; +import algoliasearch from "algoliasearch"; + +const adminApiKey = process.env.SECRET_ALGOLIA_ADMIN_KEY; +const appId = process.env.PUBLIC_ALGOLIA_APP_ID; +const indexName = process.env.PUBLIC_ALGOLIA_INDEX_BLOG; +const POSTS_PATH = "src/content/blog"; + +/** + * @param {string} str + * @returns + */ +async function parseMarkdown(str) { + if (!str) return; + const result = await remark().use(strip).process(str) + return result.toString() +} + +/** + * @param {string} dir + * @returns string[] + */ +function getAllFiles(dir) { + const result = fs.readdirSync(dir).reduce((files, file) => { + const name = path.join(dir, file); + const isDirectory = fs.statSync(name).isDirectory(); + // biome-ignore lint/performance/noAccumulatingSpread: + return isDirectory ? [...files, ...getAllFiles(name)] : [...files, name]; + }, []); + + return result; +} + +/** + * @param localFilePath + * ex: /home/oriverk/Codes/oriverk/blog/docs/2022/memo.md + * @returns + */ +async function getPost(localFilePath) { + const source = fs.readFileSync(localFilePath).toString(); + const { content, data } = matter(source); + const { + title, + create = "", + update = "", + published = false, + tags = [], + } = data; + const regexp = new RegExp(`${POSTS_PATH}\/|.mdx?$`, "g"); + // ex: 2022/20220505-ubuntu2204 + const id = localFilePath.replace(regexp, ""); + return { + objectID: id, + id, + title, + create, + update, + tags: tags.map((tag) => tag.toLowerCase()).sort() || "", + content: await parseMarkdown(content), + published, + }; +} + +async function getPosts() { + const fileNames = getAllFiles(POSTS_PATH) + .filter((path) => /\.mdx?$/.test(path)); + const promise = fileNames.map(async (fileName) => await getPost(fileName)); + const posts = (await Promise.all(promise)) + .filter(({ published }) => published) + .sort((a, b) => { + return ( + new Date(b.update ?? b.create).getDate() - + new Date(a.update ?? b.create).getDate() + ); + }); + return posts; +} + +async function updateAlgolia(appId, adminApiKey, data) { + const client = algoliasearch(appId, adminApiKey); + const index = client.initIndex(indexName); + + try { + await index + .saveObjects(data, { + autoGenerateObjectIDIfNotExist: true, + }) + .then(({ objectIDs }) => { + console.log("post data for was successfull pushed to Algolia!"); + console.log(objectIDs); + }); + } catch (error) { + console.log("Error occurred!"); + console.error(error.message); + } +} + +const posts = await getPosts(); +await updateAlgolia(appId, adminApiKey, posts);