mirror of
https://github.com/afoim/fuwari.git
synced 2026-01-31 09:03:18 +08:00
合并上游8个commit
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -28,3 +28,5 @@ yarn.lock
|
||||
|
||||
.vscode
|
||||
|
||||
# 忽略上游仓库
|
||||
ori
|
||||
@@ -40,6 +40,7 @@
|
||||
"katex": "^0.16.22",
|
||||
"markdown-it": "^14.1.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
"node-html-parser": "^7.0.1",
|
||||
"overlayscrollbars": "^2.11.1",
|
||||
"photoswipe": "^5.4.4",
|
||||
"reading-time": "^1.5.0",
|
||||
|
||||
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@@ -86,6 +86,9 @@ importers:
|
||||
mdast-util-to-string:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
node-html-parser:
|
||||
specifier: ^7.0.1
|
||||
version: 7.0.1
|
||||
overlayscrollbars:
|
||||
specifier: ^2.11.1
|
||||
version: 2.11.1
|
||||
@@ -2878,6 +2881,10 @@ packages:
|
||||
hastscript@9.0.1:
|
||||
resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==}
|
||||
|
||||
he@1.2.0:
|
||||
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||
hasBin: true
|
||||
|
||||
html-escaper@3.0.3:
|
||||
resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
|
||||
|
||||
@@ -3601,6 +3608,9 @@ packages:
|
||||
encoding:
|
||||
optional: true
|
||||
|
||||
node-html-parser@7.0.1:
|
||||
resolution: {integrity: sha512-KGtmPY2kS0thCWGK0VuPyOS+pBKhhe8gXztzA2ilAOhbUbxa9homF1bOyKvhGzMLXUoRds9IOmr/v5lr/lqNmA==}
|
||||
|
||||
node-mock-http@1.0.0:
|
||||
resolution: {integrity: sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==}
|
||||
|
||||
@@ -8410,6 +8420,8 @@ snapshots:
|
||||
property-information: 7.0.0
|
||||
space-separated-tokens: 2.0.2
|
||||
|
||||
he@1.2.0: {}
|
||||
|
||||
html-escaper@3.0.3: {}
|
||||
|
||||
html-void-elements@3.0.0: {}
|
||||
@@ -9339,6 +9351,11 @@ snapshots:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
node-html-parser@7.0.1:
|
||||
dependencies:
|
||||
css-select: 5.1.0
|
||||
he: 1.2.0
|
||||
|
||||
node-mock-http@1.0.0: {}
|
||||
|
||||
node-releases@2.0.19: {}
|
||||
|
||||
BIN
public/favicon.webp
Normal file
BIN
public/favicon.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
@@ -49,7 +49,7 @@ export const siteConfig: SiteConfig = {
|
||||
favicon: [
|
||||
// Leave this array empty to use the default favicon
|
||||
{
|
||||
src: "https://q2.qlogo.cn/headimg_dl?dst_uin=2726730791&spec=5", // Path of the favicon, relative to the /public directory
|
||||
src: "./favicon.webp", // Path of the favicon, relative to the /public directory
|
||||
// theme: 'light', // (Optional) Either 'light' or 'dark', set only if you have different favicons for light and dark mode
|
||||
// sizes: '32x32', // (Optional) Size of the favicon, set only if you have favicons of different sizes
|
||||
},
|
||||
@@ -85,7 +85,7 @@ export const navBarConfig: NavBarConfig = {
|
||||
};
|
||||
|
||||
export const profileConfig: ProfileConfig = {
|
||||
avatar: "https://q2.qlogo.cn/headimg_dl?dst_uin=2726730791&spec=5", // Relative to the /src directory. Relative to the /public directory if it starts with '/'
|
||||
avatar: "/favicon.webp", // Relative to the /src directory. Relative to the /public directory if it starts with '/'
|
||||
name: "二叉树树",
|
||||
bio: "爱你所爱~ ❤",
|
||||
links: [
|
||||
|
||||
BIN
src/content/assets/images/2025-08-10-21-31-04-image.png
Normal file
BIN
src/content/assets/images/2025-08-10-21-31-04-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
30
src/content/posts/folo-verification.md
Normal file
30
src/content/posts/folo-verification.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: 认证为Folo的创作者
|
||||
published: 2025-08-10T21:26:55
|
||||
description: 'Folo是一个RSS聚合平台,在上面不仅可以订阅很多优质的RSS源,也可以认领自己的RSS源'
|
||||
image: '../assets/images/2025-08-10-21-31-04-image.png'
|
||||
tags: [Folo]
|
||||
category: '记录'
|
||||
draft: false
|
||||
lang: ''
|
||||
---
|
||||
|
||||
# 这是啥?
|
||||
|
||||
这是一篇Folo认证文章,用于认证本RSS归属于我
|
||||
|
||||
This message is used to verify that this feed (feedId:154118531036739584) belongs to me (userId:165740980096046080). Join me in enjoying the next generation information browser https://folo.is.
|
||||
|
||||
# 我要怎么认证?
|
||||
|
||||
首先 你得有一个博客,或者说一个有RSS的网站
|
||||
|
||||
比如 2x.nz/rss.xml
|
||||
|
||||
接下来在Folo处点击认证 https://folo.is
|
||||
|
||||
会弹出一个内容,要求让你放置到RSS
|
||||
|
||||
最简单的方法就是像我这样新建一篇文章,然后原封不动粘贴这段话,然后认证即可
|
||||
|
||||

|
||||
@@ -18,6 +18,8 @@ QQ: 165624236 (易封,经常转生)
|
||||
|
||||
TG: https://t.me/+blyHrp_GihhhMWVl
|
||||
|
||||
Discord: https://discord.gg/qaCDqsGA
|
||||
|
||||
Matrix: m.2x.nz [详细教程](/posts/element/)
|
||||
|
||||
Microsoft Team: https://teams.live.com/l/community/FBA6DNy_XOUr-3vxwI?v=g1
|
||||
@@ -1,33 +1,84 @@
|
||||
import { siteConfig } from "@/config";
|
||||
import rss from "@astrojs/rss";
|
||||
import { getSortedPosts } from "@utils/content-utils";
|
||||
import type { APIContext } from "astro";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
import rss from '@astrojs/rss';
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { siteConfig } from '@/config';
|
||||
import { parse as htmlParser } from 'node-html-parser';
|
||||
import { getImage } from 'astro:assets';
|
||||
import type { APIContext, ImageMetadata } from 'astro';
|
||||
import type { RSSFeedItem } from '@astrojs/rss';
|
||||
import { getSortedPosts } from '@/utils/content-utils';
|
||||
|
||||
const parser = new MarkdownIt();
|
||||
const markdownParser = new MarkdownIt();
|
||||
|
||||
// get dynamic import of images as a map collection
|
||||
const imagesGlob = import.meta.glob<{ default: ImageMetadata }>(
|
||||
'/src/content/**/*.{jpeg,jpg,png,gif,webp}', // include posts and assets
|
||||
);
|
||||
|
||||
export async function GET(context: APIContext) {
|
||||
const blog = await getSortedPosts();
|
||||
if (!context.site) {
|
||||
throw Error('site not set');
|
||||
}
|
||||
|
||||
// Use the same ordering as site listing (pinned first, then by published desc)
|
||||
const posts = await getSortedPosts();
|
||||
const feed: RSSFeedItem[] = [];
|
||||
|
||||
for (const post of posts) {
|
||||
// convert markdown to html string
|
||||
const body = markdownParser.render(post.body);
|
||||
// convert html string to DOM-like structure
|
||||
const html = htmlParser.parse(body);
|
||||
// hold all img tags in variable images
|
||||
const images = html.querySelectorAll('img');
|
||||
|
||||
for (const img of images) {
|
||||
const src = img.getAttribute('src');
|
||||
if (!src) continue;
|
||||
|
||||
// Handle content-relative images and convert them to built _astro paths
|
||||
if (src.startsWith('./') || src.startsWith('../')) {
|
||||
let importPath: string | null = null;
|
||||
|
||||
if (src.startsWith('./')) {
|
||||
// Path relative to the post file directory
|
||||
const prefixRemoved = src.slice(2);
|
||||
importPath = `/src/content/posts/${prefixRemoved}`;
|
||||
} else {
|
||||
// Path like ../assets/images/xxx -> relative to /src/content/
|
||||
const cleaned = src.replace(/^\.\.\//, '');
|
||||
importPath = `/src/content/${cleaned}`;
|
||||
}
|
||||
|
||||
const imageMod = await imagesGlob[importPath]?.()?.then((res) => res.default);
|
||||
if (imageMod) {
|
||||
const optimizedImg = await getImage({ src: imageMod });
|
||||
img.setAttribute('src', new URL(optimizedImg.src, context.site).href);
|
||||
}
|
||||
} else if (src.startsWith('/')) {
|
||||
// images starting with `/` are in public dir
|
||||
img.setAttribute('src', new URL(src, context.site).href);
|
||||
}
|
||||
}
|
||||
|
||||
feed.push({
|
||||
title: post.data.title,
|
||||
description: post.data.description,
|
||||
pubDate: post.data.published,
|
||||
link: `/posts/${post.slug}/`,
|
||||
// sanitize the new html string with corrected image paths
|
||||
content: sanitizeHtml(html.toString(), {
|
||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']),
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
return rss({
|
||||
title: siteConfig.title,
|
||||
description: siteConfig.subtitle || "No description",
|
||||
site: context.site ?? "https://fuwari.vercel.app",
|
||||
items: blog.map((post) => {
|
||||
const content =
|
||||
typeof post.body === "string" ? post.body : String(post.body || "");
|
||||
|
||||
return {
|
||||
title: post.data.title,
|
||||
pubDate: post.data.published,
|
||||
description: post.data.description || "",
|
||||
link: `/posts/${post.slug}/`,
|
||||
content: sanitizeHtml(parser.render(content), {
|
||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
|
||||
}),
|
||||
};
|
||||
}),
|
||||
description: siteConfig.subtitle || 'No description',
|
||||
site: context.site,
|
||||
items: feed,
|
||||
customData: `<language>${siteConfig.lang}</language>`,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user