From 7039b10df2f5429a6c270b47b320b3727d64d951 Mon Sep 17 00:00:00 2001 From: Pacharapol Withayasakpunt Date: Tue, 15 Dec 2020 18:42:00 +0700 Subject: [PATCH] update --- _posts/千字文/千字文1.1.md | 4 +- _posts/千字文/千字文1.2.md | 4 +- _posts/千字文/千字文1.3.md | 4 +- _posts/千字文/千字文1.4.md | 4 +- _posts/千字文/千字文1.5.md | 4 +- _posts/千字文/千字文1.6.md | 4 +- _posts/千字文/千字文1.7.md | 4 +- _posts/千字文/千字文1.8.md | 4 +- _posts/千字文/千字文1.9.md | 2 +- _posts/千字文/千字文2.1.md | 4 +- _posts/千字文/千字文2.2.md | 4 +- _posts/千字文/千字文2.3.md | 2 +- _posts/千字文/千字文2.4.md | 4 +- _posts/千字文/千字文2.5.md | 4 +- _posts/千字文/千字文2.6.md | 4 +- _posts/千字文/千字文2.7.md | 4 +- _posts/千字文/千字文2.8.md | 4 +- _posts/千字文/千字文2.9.md | 4 +- _posts/千字文/千字文3.1.md | 4 +- _posts/千字文/千字文3.2.md | 4 +- _posts/千字文/千字文3.3.md | 4 +- packages/nuxt/.eslintrc.js | 4 +- packages/nuxt/assets/schema.ts | 56 ------------ packages/nuxt/nuxt.config.ts | 82 ++++++++++------- packages/nuxt/package.json | 5 +- packages/nuxt/scripts/dir.ts | 11 +-- packages/nuxt/scripts/make-html.ts | 24 ++--- packages/nuxt/scripts/prepare.ts | 50 ++++------- packages/nuxt/server/db.ts | 99 +++++++++++++++++++++ packages/nuxt/server/theme.ts | 55 ++++++++++++ packages/nuxt/yarn.lock | 137 ++++++++++++++++++++++++++--- theme.yml | 4 +- 32 files changed, 415 insertions(+), 192 deletions(-) delete mode 100644 packages/nuxt/assets/schema.ts create mode 100644 packages/nuxt/server/db.ts create mode 100644 packages/nuxt/server/theme.ts diff --git a/_posts/千字文/千字文1.1.md b/_posts/千字文/千字文1.1.md index 6021180..369b996 100644 --- a/_posts/千字文/千字文1.1.md +++ b/_posts/千字文/千字文1.1.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/1" -date: 2019-08-11T00:00:00+07:00 -tag: +createdAt: 2019-08-11T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.2.md b/_posts/千字文/千字文1.2.md index 7081f08..3c210c8 100644 --- a/_posts/千字文/千字文1.2.md +++ b/_posts/千字文/千字文1.2.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/2" -date: 2019-08-12T00:00:00+07:00 -tag: +createdAt: 2019-08-12T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.3.md b/_posts/千字文/千字文1.3.md index 1d3b3fe..fd02c5f 100644 --- a/_posts/千字文/千字文1.3.md +++ b/_posts/千字文/千字文1.3.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/3" -date: 2019-10-08T00:00:00+07:00 -tag: +createdAt: 2019-10-08T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.4.md b/_posts/千字文/千字文1.4.md index 2e9902a..72f7804 100644 --- a/_posts/千字文/千字文1.4.md +++ b/_posts/千字文/千字文1.4.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/4" -date: "2019-08-14" -tag: +createdAt: 2019-08-14T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.5.md b/_posts/千字文/千字文1.5.md index e74762a..72aa26c 100644 --- a/_posts/千字文/千字文1.5.md +++ b/_posts/千字文/千字文1.5.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/5" -date: "2019-08-15" -tag: +createdAt: 2019-08-15T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.6.md b/_posts/千字文/千字文1.6.md index 0ae442c..c697be2 100644 --- a/_posts/千字文/千字文1.6.md +++ b/_posts/千字文/千字文1.6.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/6" -date: "2019-08-16" -tag: +createdAt: 2019-08-16T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.7.md b/_posts/千字文/千字文1.7.md index 7854a62..6a432a9 100644 --- a/_posts/千字文/千字文1.7.md +++ b/_posts/千字文/千字文1.7.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/7" -date: "2019-08-17" -tag: +createdAt: 2019-08-17T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.8.md b/_posts/千字文/千字文1.8.md index cb4533c..20e61bb 100644 --- a/_posts/千字文/千字文1.8.md +++ b/_posts/千字文/千字文1.8.md @@ -1,7 +1,7 @@ --- title: "千字文 - 1/8" -date: "2019-08-18" -tag: +createdAt: 2019-08-18T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文1.9.md b/_posts/千字文/千字文1.9.md index 605c9f2..87f84b0 100644 --- a/_posts/千字文/千字文1.9.md +++ b/_posts/千字文/千字文1.9.md @@ -1,6 +1,6 @@ --- title: "千字文 - 1/9" -date: "2019-08-19" +createdAt: 2019-08-19T00:00:00+07:00 tag: - 千字文 - 汉字 diff --git a/_posts/千字文/千字文2.1.md b/_posts/千字文/千字文2.1.md index 243b6b9..715e3b4 100644 --- a/_posts/千字文/千字文2.1.md +++ b/_posts/千字文/千字文2.1.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/1" -date: "2019-08-20" -tag: +createdAt: 2019-08-20T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文2.2.md b/_posts/千字文/千字文2.2.md index 2e5ab8e..e08039b 100644 --- a/_posts/千字文/千字文2.2.md +++ b/_posts/千字文/千字文2.2.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/2" -date: "2019-08-21" -tag: +createdAt: 2019-08-21T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文2.3.md b/_posts/千字文/千字文2.3.md index be76dff..ee8cbe8 100644 --- a/_posts/千字文/千字文2.3.md +++ b/_posts/千字文/千字文2.3.md @@ -1,6 +1,6 @@ --- title: "千字文 - 2/3" -date: "2019-08-23" +createdAt: 2019-08-23T00:00:00+07:00 tag: - 千字文 - 汉字 diff --git a/_posts/千字文/千字文2.4.md b/_posts/千字文/千字文2.4.md index 1b14acf..a479c8b 100644 --- a/_posts/千字文/千字文2.4.md +++ b/_posts/千字文/千字文2.4.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/4" -date: "2019-08-27" -tag: +createdAt: 2019-08-27T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文2.5.md b/_posts/千字文/千字文2.5.md index 5efa95a..eaa9dac 100644 --- a/_posts/千字文/千字文2.5.md +++ b/_posts/千字文/千字文2.5.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/5" -date: "2019-08-29" -tag: +createdAt: 2019-08-29T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文2.6.md b/_posts/千字文/千字文2.6.md index 0a6ca29..d3293ab 100644 --- a/_posts/千字文/千字文2.6.md +++ b/_posts/千字文/千字文2.6.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/6" -date: "2019-08-30" -tag: +createdAt: 2019-08-30T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文2.7.md b/_posts/千字文/千字文2.7.md index fdd6b89..702896f 100644 --- a/_posts/千字文/千字文2.7.md +++ b/_posts/千字文/千字文2.7.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/7" -date: "2019-09-01" -tag: +createdAt: 2019-09-01T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文2.8.md b/_posts/千字文/千字文2.8.md index 919c1ca..7aa3dc4 100644 --- a/_posts/千字文/千字文2.8.md +++ b/_posts/千字文/千字文2.8.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/8" -date: "2019-09-02" -tag: +createdAt: 2019-09-02T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文2.9.md b/_posts/千字文/千字文2.9.md index af67c97..0d60f61 100644 --- a/_posts/千字文/千字文2.9.md +++ b/_posts/千字文/千字文2.9.md @@ -1,7 +1,7 @@ --- title: "千字文 - 2/9" -date: "2019-09-03" -tag: +createdAt: 2019-09-03T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文3.1.md b/_posts/千字文/千字文3.1.md index 78e8cb5..406e23f 100644 --- a/_posts/千字文/千字文3.1.md +++ b/_posts/千字文/千字文3.1.md @@ -1,7 +1,7 @@ --- title: "千字文 - 3/1" -date: "2019-09-12" -tag: +createdAt: 2019-09-12T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文3.2.md b/_posts/千字文/千字文3.2.md index 6ebbc64..2e250c1 100644 --- a/_posts/千字文/千字文3.2.md +++ b/_posts/千字文/千字文3.2.md @@ -1,7 +1,7 @@ --- title: "千字文 - 3/2" -date: "2019-09-15" -tag: +createdAt: 2019-09-15T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/_posts/千字文/千字文3.3.md b/_posts/千字文/千字文3.3.md index a4515d8..283f400 100644 --- a/_posts/千字文/千字文3.3.md +++ b/_posts/千字文/千字文3.3.md @@ -1,7 +1,7 @@ --- title: "千字文 - 3/3" -date: "2019-09-23" -tag: +createdAt: 2019-09-23T00:00:00+07:00 +tag: - 千字文 - 汉字 --- diff --git a/packages/nuxt/.eslintrc.js b/packages/nuxt/.eslintrc.js index 08335fa..8df71c0 100644 --- a/packages/nuxt/.eslintrc.js +++ b/packages/nuxt/.eslintrc.js @@ -13,5 +13,7 @@ module.exports = { ], plugins: ['prettier'], // add your custom rules here - rules: {}, + rules: { + 'require-await': 0, + }, } diff --git a/packages/nuxt/assets/schema.ts b/packages/nuxt/assets/schema.ts deleted file mode 100644 index 87fcbe9..0000000 --- a/packages/nuxt/assets/schema.ts +++ /dev/null @@ -1,56 +0,0 @@ -import sqlite3 from 'better-sqlite3' - -export interface IPost { - slug: string - date?: Date - title: string - image?: string - tag?: string[] - /** - * cleaned markdown - */ - content: string - excerptHtml: string - contentHtml: string -} - -export class Database { - db: sqlite3.Database - - constructor(public filepath: string) { - this.db = sqlite3(filepath) - } - - public init(): void { - this.db.exec(/* sql */ ` - CREATE VIRTUAL TABLE q USING fts5 ( - slug, - [date] UNINDEXED, -- epoch milli - title, - [image] UNINDEXED, - tag, -- space separated - content, -- cleaned markdown - excerptHtml UNINDEXED, - contentHtml UNINDEXED - ); - `) - } - - public insert(...ps: IPost[]): void { - const stmt = this.db.prepare(/* sql */ ` - INSERT INTO q (slug, [date], title, [image], tag, content, excerptHtml, contentHtml) - VALUES (@slug, @date, @title, @image, @tag, @content, @excerptHtml, @contentHtml) - `) - - this.db.transaction(() => { - // eslint-disable-next-line array-callback-return - ps.map((p) => { - stmt.run({ - ...p, - date: p.date ? p.date.getTime() : undefined, - tag: (p.tag || []).join(' '), - }) - }) - })() - } -} diff --git a/packages/nuxt/nuxt.config.ts b/packages/nuxt/nuxt.config.ts index 23adee8..3e268cf 100644 --- a/packages/nuxt/nuxt.config.ts +++ b/packages/nuxt/nuxt.config.ts @@ -1,39 +1,53 @@ -export default { - // Global page headers (https://go.nuxtjs.dev/config-head) - head: { - title: 'zhdiary', - meta: [ - { charset: 'utf-8' }, - { name: 'viewport', content: 'width=device-width, initial-scale=1' }, - { hid: 'description', name: 'description', content: '' }, +import { NuxtConfig } from '@nuxt/types' + +import { getTheme } from './server/theme' + +const config = async (): Promise => { + const theme = getTheme() + + return { + // Global page headers (https://go.nuxtjs.dev/config-head) + head: { + title: theme.title, + meta: [ + { charset: 'utf-8' }, + { name: 'viewport', content: 'width=device-width, initial-scale=1' }, + { + hid: 'description', + name: 'description', + content: theme.description || '', + }, + ], + link: [{ rel: 'icon', type: 'image/x-icon', href: '/media/favicon.ico' }], + }, + + // Global CSS (https://go.nuxtjs.dev/config-css) + css: [], + + // Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins) + plugins: [], + + // Auto import components (https://go.nuxtjs.dev/config-components) + components: true, + + // Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules) + buildModules: [ + // https://go.nuxtjs.dev/typescript + '@nuxt/typescript-build', ], - link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }], - }, - // Global CSS (https://go.nuxtjs.dev/config-css) - css: [], + // Modules (https://go.nuxtjs.dev/config-modules) + modules: [ + // https://go.nuxtjs.dev/axios + '@nuxtjs/axios', + ], - // Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins) - plugins: [], + // Axios module configuration (https://go.nuxtjs.dev/config-axios) + axios: {}, - // Auto import components (https://go.nuxtjs.dev/config-components) - components: true, - - // Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules) - buildModules: [ - // https://go.nuxtjs.dev/typescript - '@nuxt/typescript-build', - ], - - // Modules (https://go.nuxtjs.dev/config-modules) - modules: [ - // https://go.nuxtjs.dev/axios - '@nuxtjs/axios', - ], - - // Axios module configuration (https://go.nuxtjs.dev/config-axios) - axios: {}, - - // Build Configuration (https://go.nuxtjs.dev/config-build) - build: {}, + // Build Configuration (https://go.nuxtjs.dev/config-build) + build: {}, + } } + +export default config diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index e6ab605..a41dbf2 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -12,13 +12,15 @@ "ts": "ts-node -O '{\"module\":\"commonjs\"}'" }, "dependencies": { + "@types/express": "^4.17.9", + "@types/js-yaml": "^3.12.5", "@nuxt/typescript-runtime": "^2.0.0", "@nuxtjs/axios": "^5.12.2", "@patarapolw/scope-css": "^1.3.0", - "@types/js-yaml": "^3.12.5", "better-sqlite3": "^7.1.1", "cheerio": "^1.0.0-rc.3", "core-js": "^3.6.5", + "express": "^4.17.1", "js-yaml": "^3.14.1", "nuxt": "^2.14.6", "showdown": "^1.9.1", @@ -42,6 +44,7 @@ "eslint-plugin-nuxt": "^1.0.0", "eslint-plugin-prettier": "^3.1.4", "import-sort-parser-typescript": "^6.0.0", + "nodejieba": "^2.5.1", "prettier": "^2.1.2", "ts-node": "^9.1.1", "typescript": "4.0.5" diff --git a/packages/nuxt/scripts/dir.ts b/packages/nuxt/scripts/dir.ts index 7e4f29f..d48118c 100644 --- a/packages/nuxt/scripts/dir.ts +++ b/packages/nuxt/scripts/dir.ts @@ -3,6 +3,8 @@ import path from 'path' import dotenv from 'dotenv' +import { THEME_FILENAME } from '../server/theme' + dotenv.config({ path: '../../.env' }) dotenv.config() @@ -11,11 +13,10 @@ export const CONTENT_PATH = path.resolve( (fs.existsSync('../../_posts') ? '../..' : 'content') ) -export const srcPostPath = (...ps: string[]): string => - path.join(CONTENT_PATH, '_posts', ...ps) - -export const srcMediaPath = (...ps: string[]): string => - path.join(CONTENT_PATH, '_media', ...ps) +export const srcPath = ( + root: '_post' | '_media' | typeof THEME_FILENAME, + ...ps: string[] +): string => path.join(CONTENT_PATH, root, ...ps) export const builtPath = (...ps: string[]): string => path.join(__dirname, '../built', ...ps) diff --git a/packages/nuxt/scripts/make-html.ts b/packages/nuxt/scripts/make-html.ts index 68b3f5b..bc7178f 100644 --- a/packages/nuxt/scripts/make-html.ts +++ b/packages/nuxt/scripts/make-html.ts @@ -2,10 +2,11 @@ import crypto from 'crypto' import scopeCss from '@patarapolw/scope-css' import cheerio from 'cheerio' +import jieba from 'nodejieba' import showdown from 'showdown' export class MakeHTML { - $ = cheerio.load(''); + $ = cheerio.load('') mdConverter = new showdown.Converter({ noHeaderId: true, @@ -20,10 +21,10 @@ export class MakeHTML { backslashEscapesHTMLTags: true, emoji: true, underline: true, - metadata: true - }); + metadata: true, + }) - constructor (private slug: string) { + constructor(private slug: string) { /** * ! For some reasons default underscore italic fails to render... */ @@ -31,13 +32,13 @@ export class MakeHTML { { type: 'lang', regex: /([^\\])_{1}(.*?[^\\])_{1}/g, - replace: '$1$2' + replace: '$1$2', }, 'underscore-italic' ) } - parse (md: string): string { + parse(md: string): string { const id = 'md-' + crypto @@ -51,17 +52,20 @@ export class MakeHTML { $div.html(this.mdConverter.makeHtml(md)) $div.find('style').each((_, el) => { const $el = this.$(el) - $el.html(scopeCss($el.html(), `#${id}`)) + const html = $el.html() || '' + if (html.trim()) { + $el.html(scopeCss(html, `#${id}`)) + } }) - return this.$('
').append($div).html() + return this.$('
').append($div).html() || '' } - clean (md: string): string { + clean(md: string): string { const $div = this.$('
') $div.html(this.mdConverter.makeHtml(md)) $div.remove('style') - return $div.html() + return jieba.cutForSearch($div.html() || '').join(' ') } } diff --git a/packages/nuxt/scripts/prepare.ts b/packages/nuxt/scripts/prepare.ts index b7bde54..fa1eb36 100644 --- a/packages/nuxt/scripts/prepare.ts +++ b/packages/nuxt/scripts/prepare.ts @@ -2,53 +2,40 @@ import fg from 'fast-glob' import fs from 'fs-extra' import yaml from 'js-yaml' import rimraf from 'rimraf' -import * as z from 'zod' -import { Database } from '../assets/schema' -import { builtPath, dstMediaPath, srcMediaPath, srcPostPath } from './dir' +import { Database, IMatter } from '../server/db' +import { THEME_FILENAME } from '../server/theme' +import { builtPath, dstMediaPath, srcPath } from './dir' import { MakeHTML } from './make-html' async function main() { rimraf.sync(dstMediaPath()) rimraf.sync(builtPath()) - await fs.copy(srcMediaPath(), dstMediaPath()) + await fs.copy(srcPath('_media'), dstMediaPath()) await fs.ensureDir(builtPath()) + await fs.copyFile(srcPath(THEME_FILENAME), builtPath(THEME_FILENAME)) + const db = new Database(builtPath('data.db')) db.init() const files = await fg('**/*.md', { - cwd: srcPostPath(), + cwd: srcPath('_post'), }) // eslint-disable-next-line array-callback-return files.map((f) => { - const slug = f.replace(/^.+\//, '').replace(/\.md$/, '') - let header: Record = {} - let markdown = fs.readFileSync(srcPostPath(f), 'utf8') + const path = f.replace(/\.md$/, '') + let markdown = fs.readFileSync(srcPath('_post', f), 'utf8') - if (markdown.startsWith('---\n')) { - const [h, c = ''] = markdown.substr(4).split(/---\n(.*)$/s) - header = yaml.safeLoad(h, { - schema: yaml.JSON_SCHEMA, - }) as Record - markdown = c - } + const [h, c = ''] = markdown.substr(4).split(/---\n(.*)$/s) + const header = yaml.safeLoad(h, { + schema: yaml.JSON_SCHEMA, + }) as IMatter + markdown = c - const makeHtml = new MakeHTML(slug) - - const { title, date, image, tag } = (() => { - const { title, date, image, tag } = header - return z - .object({ - title: z.string(), - date: z.date().optional(), - image: z.string().optional(), - tag: z.array(z.string()).optional(), - }) - .parse({ title, date, image, tag }) - })() + const makeHtml = new MakeHTML(path) const content = makeHtml.clean(markdown) const excerptHtml = makeHtml.parse( @@ -57,11 +44,8 @@ async function main() { const contentHtml = makeHtml.parse(markdown) db.insert({ - slug, - title, - date, - image, - tag, + ...header, + path, content, excerptHtml, contentHtml, diff --git a/packages/nuxt/server/db.ts b/packages/nuxt/server/db.ts new file mode 100644 index 0000000..05651f6 --- /dev/null +++ b/packages/nuxt/server/db.ts @@ -0,0 +1,99 @@ +import sqlite3 from 'better-sqlite3' +import * as z from 'zod' + +const zMatter = z.object({ + date: z.date().optional(), + createdAt: z.date().optional(), + updatedAt: z.date().optional(), + title: z.string(), + image: z.string().optional(), + tag: z.array(z.string()).optional(), + category: z.string().optional(), +}) + +export type IMatter = z.infer + +export const zPost = z + .object({ + path: z.string(), + /** + * Cleaned and jieba-separated markdown + */ + content: z.string(), + excerptHtml: z.string(), + contentHtml: z.string(), + }) + .merge(zMatter.nonstrict()) + +export type IPost = z.infer + +export class Database { + db: sqlite3.Database + + constructor(public filepath: string, opts?: sqlite3.Options) { + this.db = sqlite3(filepath, opts) + } + + public init(): void { + this.db.exec(/* sql */ ` + CREATE TABLE IF NOT EXISTS files ( + [path] TEXT PRIMARY KEY, + [date] INT, -- epoch milli + [createdAt] INT, -- epoch milli + [updatedAt] INT, -- epoch milli + -- q.title + [image] TEXT, + -- q.tag.split(/ /g) + -- q.category + -- q.content + excerptHtml TEXT NOT NULL, + contentHtml TEXT NOT NULL + ); + + CREATE INDEX IF NOT EXISTS files_date ON files([date]); + CREATE INDEX IF NOT EXISTS files_createdAt ON files(createdAt); + CREATE INDEX IF NOT EXISTS files_updatedAt ON files(updatedAt); + `) + + this.db.exec(/* sql */ ` + CREATE VIRTUAL TABLE IF NOT EXISTS q USING fts5 ( + [path], -- REFERENCES files([path]) + title, + tag, -- space separated + category, -- can compare via equal + content -- cleaned markdown + ); + `) + } + + public insert(...ps: IPost[]): void { + const fStmt = this.db.prepare(/* sql */ ` + INSERT INTO files ([path], [date], [createdAt], [updatedAt], [image], excerptHtml, contentHtml) + VALUES (@path, @date, @createdAt, @updatedAt, @image, @excerptHtml, @contentHtml) + `) + + const qStmt = this.db.prepare(/* sql */ ` + INSERT INTO q ([path], title, tag, category, content) + VALUES (@path, @title, @tag, @category, @content) + `) + + this.db.transaction(() => { + // eslint-disable-next-line array-callback-return + ps.map((p) => { + p = zPost.parse(p) + + fStmt.run({ + ...p, + date: p.date ? p.date.getTime() : undefined, + createdAt: p.createdAt ? p.createdAt.getTime() : undefined, + updatedAt: p.updatedAt ? p.updatedAt.getTime() : undefined, + }) + + qStmt.run({ + ...p, + tag: p.tag ? p.tag.join(' ') : undefined, + }) + }) + })() + } +} diff --git a/packages/nuxt/server/theme.ts b/packages/nuxt/server/theme.ts new file mode 100644 index 0000000..3ce33a7 --- /dev/null +++ b/packages/nuxt/server/theme.ts @@ -0,0 +1,55 @@ +import fs from 'fs' + +import yaml from 'js-yaml' +import * as z from 'zod' + +export const THEME_FILENAME = 'theme.yml' + +export const zTheme = z + .object({ + title: z.string(), + description: z.string().optional(), + keywords: z.array(z.string()).optional(), + nav: z + .array( + z + .object({ + name: z.string(), + to: z.string(), + }) + .or( + z.object({ + name: z.string(), + href: z.string(), + }) + ) + ) + .optional(), + author: z + .object({ + url: z.string().optional(), + email: z.string().optional(), + name: z.string(), + }) + .nonstrict(), + analytics: z + .object({ + plausible: z.string().optional(), + }) + .optional(), + comment: z + .object({ + remark42: z + .object({ + host: z.string(), + siteId: z.string(), + }) + .optional(), + }) + .optional(), + }) + .nonstrict() + +export function getTheme() { + return zTheme.parse(yaml.safeLoad(fs.readFileSync(THEME_FILENAME, 'utf-8'))) +} diff --git a/packages/nuxt/yarn.lock b/packages/nuxt/yarn.lock index 16c7a19..3fb88b6 100644 --- a/packages/nuxt/yarn.lock +++ b/packages/nuxt/yarn.lock @@ -1425,7 +1425,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express@*": +"@types/express@*", "@types/express@^4.17.9": version "4.17.9" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.9.tgz#f5f2df6add703ff28428add52bdec8a1091b0a78" integrity sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw== @@ -2005,6 +2005,11 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -3474,6 +3479,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" +debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" @@ -3585,7 +3597,7 @@ detect-indent@^5.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= -detect-libc@^1.0.3: +detect-libc@^1.0.2, detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= @@ -4250,7 +4262,7 @@ expand-template@^2.0.3: resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== -express@^4.16.3: +express@^4.16.3, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== @@ -5070,7 +5082,7 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -5094,6 +5106,13 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= +ignore-walk@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + dependencies: + minimatch "^3.0.4" + ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -6028,7 +6047,7 @@ minipass-pipeline@^1.2.2: dependencies: minipass "^3.0.0" -minipass@^2.3.5, minipass@^2.6.0, minipass@^2.9.0: +minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== @@ -6113,6 +6132,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + multimap@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multimap/-/multimap-1.1.0.tgz#5263febc085a1791c33b59bb3afc6a76a2a10ca8" @@ -6165,6 +6189,15 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +needle@^2.2.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.5.2.tgz#cf1a8fce382b5a280108bba90a14993c00e4010a" + integrity sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -6197,6 +6230,11 @@ node-abi@^2.7.0: dependencies: semver "^5.4.1" +node-addon-api@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.2.tgz#04bc7b83fd845ba785bb6eae25bc857e1ef75681" + integrity sha512-+D4s2HCnxPd5PjjI0STKwncjXTUKKqm74MDMz9OPXavjsGmjkvwgLtA5yoxJUdmpj52+2u+RrXgPipahKczMKg== + node-fetch@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" @@ -6243,6 +6281,22 @@ node-object-hash@^1.2.0: resolved "https://registry.yarnpkg.com/node-object-hash/-/node-object-hash-1.4.2.tgz#385833d85b229902b75826224f6077be969a9e94" integrity sha512-UdS4swXs85fCGWWf6t6DMGgpN/vnlKeSGEQ7hJcrs7PBFoxoKLmibc3QRb7fwiYsjdL7PX8iI/TMSlZ90dgHhQ== +node-pre-gyp@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" + integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4.4.2" + node-releases@^1.1.67: version "1.1.67" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12" @@ -6259,11 +6313,27 @@ node-res@^5.0.1: on-finished "^2.3.0" vary "^1.1.2" +nodejieba@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/nodejieba/-/nodejieba-2.5.1.tgz#626cc93a104b96de6ce85f59b640fb316d4b763c" + integrity sha512-VnJBQSl2G8swDf3ZAXMbXrMCrGFO+kVKbkB93OaBthGbEG5BrxfD8I2m7auaRX8E5C1t+hlwo3HCmQOWKkiZ9A== + dependencies: + node-addon-api "^3.0.2" + node-pre-gyp "^0.14.0" + noop-logger@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= +nopt@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -6306,6 +6376,27 @@ normalize-url@^3.0.0, normalize-url@^3.3.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== +npm-bundled@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-packlist@^1.1.6: + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" + npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -6313,7 +6404,7 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -npmlog@^4.0.1: +npmlog@^4.0.1, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -6483,11 +6574,24 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-tmpdir@~1.0.2: +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + p-finally@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" @@ -7932,7 +8036,7 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: +rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -8007,7 +8111,7 @@ safe-regex@^2.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@~1.2.4: +sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -8048,7 +8152,7 @@ schema-utils@^3.0.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -8689,6 +8793,19 @@ tar@4.4.10: safe-buffer "^5.1.2" yallist "^3.0.3" +tar@^4.4.2: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + term-size@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" diff --git a/theme.yml b/theme.yml index 33fc189..4eb3109 100644 --- a/theme.yml +++ b/theme.yml @@ -7,7 +7,7 @@ keywords: - patarapolw - chinese - mandarin -tabs: +nav: - name: 千字文 to: /post/2019/08/千字文 author: @@ -19,7 +19,7 @@ sidebar: twitter: ChinesePol analytics: plausible: zhdiary.polv.cc -comments: +comment: remark42: host: https://remark42.polv.cc siteId: zhdiary