forgor lol
This commit is contained in:
parent
869f3dfbe3
commit
862b11b9ef
34 changed files with 516 additions and 179 deletions
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { calculateReadingTime, ReadingTimeResult } from "./blog.ts";
|
||||
import { withInterval } from "./temp.ts";
|
||||
|
||||
export interface Report {
|
||||
|
|
@ -14,6 +15,7 @@ export interface Report {
|
|||
createdAt: string;
|
||||
tags?: string[];
|
||||
visibility: string;
|
||||
readingTime: ReadingTimeResult;
|
||||
date: Date;
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +61,7 @@ export async function getPosts(cursor?: string): Promise<Report[]> {
|
|||
...value,
|
||||
rkey: rkey(uri),
|
||||
date: new Date(value.createdAt),
|
||||
readingTime: value.content ? calculateReadingTime(value.content) : 1,
|
||||
createdAt: new Date(value.createdAt).toISOString().slice(0, 10).replace(
|
||||
/-/g,
|
||||
".",
|
||||
|
|
@ -82,6 +85,9 @@ export async function retrieveReport(rkey: string): Promise<Report | null> {
|
|||
|
||||
return {
|
||||
...response.value,
|
||||
readingTime: response.value.content
|
||||
? calculateReadingTime(response.value.content)
|
||||
: 1,
|
||||
cid: response.cid,
|
||||
rkey,
|
||||
} as Report;
|
||||
|
|
|
|||
68
utils/blog.ts
Normal file
68
utils/blog.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export interface ReadingTimeOptions {
|
||||
wordsPerMinute?: number;
|
||||
imageTime?: number;
|
||||
codeBlockTime?: number;
|
||||
chineseKoreanReadingSpeed?: number;
|
||||
}
|
||||
|
||||
export interface ReadingTimeResult {
|
||||
minutes: number;
|
||||
words: number;
|
||||
images: number;
|
||||
codeBlocks: number;
|
||||
}
|
||||
|
||||
export function formatReadingTime(input: ReadingTimeResult) {
|
||||
return `${input.words} words · ${
|
||||
input.images ? `${input.images} images · ` : ""
|
||||
}${
|
||||
input.codeBlocks ? `${input.codeBlocks} code blocks · ` : ""
|
||||
}${input.minutes} minutes`;
|
||||
}
|
||||
|
||||
export function calculateReadingTime(
|
||||
input: string,
|
||||
options: ReadingTimeOptions = {},
|
||||
): ReadingTimeResult {
|
||||
const {
|
||||
wordsPerMinute = 200,
|
||||
imageTime = 12,
|
||||
codeBlockTime = 15,
|
||||
chineseKoreanReadingSpeed = 260,
|
||||
} = options;
|
||||
|
||||
let images = 0, preBlocks = 0, codeBlocks = 0;
|
||||
|
||||
const text = input
|
||||
.replace(/<img[^>]*>/gi, () => (images++, ""))
|
||||
.replace(/<pre[^>]*>[\s\S]*?<\/pre>/gi, () => (preBlocks++, ""))
|
||||
.replace(/<code[^>]*>[\s\S]*?<\/code>/gi, () => (codeBlocks++, ""));
|
||||
|
||||
const cjkRegex = /[\u4E00-\u9FFF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]/g;
|
||||
const cjkMatches = text.match(cjkRegex);
|
||||
const cjkCharacters = cjkMatches?.length ?? 0;
|
||||
|
||||
const textWithoutCJK = cjkCharacters ? text.replace(cjkRegex, " ") : text;
|
||||
const words = textWithoutCJK.trim().split(/\s+/).reduce(
|
||||
(n, w) => n + (w && /\w/.test(w) ? 1 : 0),
|
||||
0,
|
||||
);
|
||||
|
||||
const totalMinutes = Math.ceil(
|
||||
words / wordsPerMinute +
|
||||
cjkCharacters / chineseKoreanReadingSpeed +
|
||||
(images * imageTime + (preBlocks + codeBlocks) * codeBlockTime) / 60,
|
||||
);
|
||||
|
||||
return {
|
||||
minutes: Math.max(totalMinutes || 2, 2),
|
||||
words: words + cjkCharacters,
|
||||
images,
|
||||
codeBlocks: preBlocks + codeBlocks,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright (c) 2025 favewa
|
||||
* Copyright (c) 2025 miwa
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue