mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-10 23:34:38 +08:00
feat: use jsx (#14863)
* feat: render rss using jsx * fix: error page response header * feat: render atom using jsx * feat: export art * feat: use jsxRenderer * chore: upgrade hono
This commit is contained in:
@@ -12,6 +12,7 @@ import debug from '@/middleware/debug';
|
||||
import header from '@/middleware/header';
|
||||
import antiHotlink from '@/middleware/anti-hotlink';
|
||||
import parameter from '@/middleware/parameter';
|
||||
import { jsxRenderer } from 'hono/jsx-renderer';
|
||||
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
@@ -27,6 +28,13 @@ const app = new Hono();
|
||||
|
||||
app.use(compress());
|
||||
|
||||
app.use(jsxRenderer(
|
||||
({ children }) => <>{children}</>,
|
||||
{
|
||||
docType: '<?xml version="1.0" encoding="UTF-8"?>',
|
||||
stream: {}
|
||||
}
|
||||
));
|
||||
app.use(mLogger);
|
||||
app.use(sentry);
|
||||
app.use(accessControl);
|
||||
@@ -1,4 +1,4 @@
|
||||
import { rss3Ums, json, art } from '@/utils/render';
|
||||
import { rss3Ums, json, RSS, Atom } from '@/utils/render';
|
||||
import * as path from 'node:path';
|
||||
import { config } from '@/config';
|
||||
import { collapseWhitespace, convertDateToISO8601 } from '@/utils/common-utils';
|
||||
@@ -26,9 +26,6 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
||||
}
|
||||
}
|
||||
|
||||
const templateName = outputType === 'atom' ? 'atom.art' : 'rss.art';
|
||||
const template = path.resolve(__dirname, `../views/${templateName}`);
|
||||
|
||||
if (data) {
|
||||
data.title = collapseWhitespace(data.title) || '';
|
||||
data.description && (data.description = collapseWhitespace(data.description) || '');
|
||||
@@ -93,8 +90,10 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
||||
return ctx.body(json(result));
|
||||
} else if (ctx.get('no-content')) {
|
||||
return ctx.body(null);
|
||||
} else if (outputType === 'atom') {
|
||||
return ctx.render(<Atom data={result} />);
|
||||
} else {
|
||||
return ctx.body(art(template, result));
|
||||
return ctx.render(<RSS data={result} />);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,6 +24,8 @@ export type DataItem = {
|
||||
enclosure_title?: string;
|
||||
enclosure_length?: number;
|
||||
itunes_duration?: number | string;
|
||||
itunes_item_image?: string;
|
||||
media?: Record<string, Record<string, string>>;
|
||||
|
||||
_extra?: Record<string, any> & {
|
||||
links?: {
|
||||
@@ -45,6 +47,13 @@ export type Data = {
|
||||
language?: string;
|
||||
feedLink?: string;
|
||||
lastBuildDate?: string;
|
||||
itunes_author?: string;
|
||||
itunes_category?: string;
|
||||
itunes_explicit?: string | boolean;
|
||||
id?: string;
|
||||
|
||||
atomlink?: string;
|
||||
ttl?: number;
|
||||
};
|
||||
|
||||
// namespace
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export { default as rss3Ums } from '@/views/rss3-ums';
|
||||
export { default as json } from '@/views/json';
|
||||
export { default as RSS } from '@/views/rss';
|
||||
export { default as Atom } from '@/views/atom';
|
||||
export { default as art } from 'art-template';
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:rsshub="http://rsshub.app/xml/schemas">
|
||||
<generator>RSSHub</generator>
|
||||
<webMaster>i@diygod.me (DIYgod)</webMaster>
|
||||
<language>{{ language || 'zh-cn' }}</language>
|
||||
<id>{{ id || link }}</id>
|
||||
<title><![CDATA[{{@ title || 'RSSHub' }}]]></title>
|
||||
|
||||
{{ if subtitle }}
|
||||
<subtitle><![CDATA[{{@ subtitle }}]]></subtitle>
|
||||
{{ /if }}
|
||||
|
||||
<updated>{{ updated }}</updated>
|
||||
<link href="{{ link }}" />
|
||||
<author>
|
||||
<name><![CDATA[{{@ author || 'RSSHub' }}]]></name>
|
||||
</author>
|
||||
|
||||
{{if contributor }}
|
||||
{{ each contributor }}
|
||||
<contributor>
|
||||
<name><![CDATA[{{@ $value }}]]></name>
|
||||
</contributor>
|
||||
{{ /each }}
|
||||
{{ /if }}
|
||||
|
||||
{{ if icon }}
|
||||
<icon>{{ icon }}</icon>
|
||||
{{ /if }}
|
||||
|
||||
{{ if logo }}
|
||||
<logo>{{ logo }}</logo>
|
||||
{{ /if }}
|
||||
|
||||
{{ each item $e }}
|
||||
<entry>
|
||||
<id>{{ $e.guid || $e.id || $e.link }}</id>
|
||||
<title><![CDATA[{{@ $e.title }}]]></title>
|
||||
|
||||
{{ if ($e.pubDate && $e.updated) }}
|
||||
<published>{{ $e.pubDate }}</published>
|
||||
{{ /if }}
|
||||
<updated>{{ $e.updated || $e.pubDate }}</updated>
|
||||
|
||||
{{ if $e.author }}
|
||||
<author>
|
||||
<name><![CDATA[{{@ $e.author || 'RSSHub' }}]]></name>
|
||||
</author>
|
||||
{{ /if }}
|
||||
|
||||
<link href="{{ $e.link }}" />
|
||||
|
||||
{{ if $e.upvotes }}
|
||||
<rsshub:upvotes>{{ $e.upvotes }}</rsshub:upvotes>
|
||||
{{ /if }}
|
||||
|
||||
{{ if $e.downvotes }}
|
||||
<rsshub:downvotes>{{ $e.downvotes }}</rsshub:downvotes>
|
||||
{{ /if }}
|
||||
|
||||
{{ if $e.comments }}
|
||||
<rsshub:comments>{{ $e.comments }}</rsshub:comments>
|
||||
{{ /if }}
|
||||
|
||||
{{ if $e.summary }}
|
||||
<summary type="html"><![CDATA[{{@ $e.summary }}]]></summary>
|
||||
{{ /if }}
|
||||
|
||||
{{ if $e.content }}
|
||||
<content type="html" src="{{ $e.link }}">{{ $e.content.html || $e.content.text }}</content>
|
||||
{{ else if $e.description }}
|
||||
<content type="html" src="{{ $e.link }}">{{ $e.description }}</content>
|
||||
{{ /if }}
|
||||
|
||||
{{ if typeof $e.category === 'string' }}
|
||||
<category term="{{ $e.category }}"></category>
|
||||
{{ else }}
|
||||
{{ each $e.category $c }}
|
||||
<category term="{{ $c }}"></category>
|
||||
{{ /each }}
|
||||
{{ /if }}
|
||||
|
||||
</entry>
|
||||
{{ /each }}
|
||||
|
||||
</feed>
|
||||
37
lib/views/atom.tsx
Normal file
37
lib/views/atom.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { FC } from 'hono/jsx';
|
||||
import { Data } from '@/types';
|
||||
|
||||
const RSS: FC<{ data: Data }> = ({ data }) => (
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:rsshub="http://rsshub.app/xml/schemas">
|
||||
<title>{data.title || 'RSSHub'}</title>
|
||||
<link href={data.link || 'https://docs.rsshub.app'} />
|
||||
<id>{ data.id || data.link }</id>
|
||||
<subtitle>{data.description || data.title} - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)</subtitle>
|
||||
<generator>RSSHub</generator>
|
||||
<webMaster>i@diygod.me (DIYgod)</webMaster>
|
||||
<language>{data.language || 'en'}</language>
|
||||
<updated>{data.lastBuildDate}</updated>
|
||||
<author>
|
||||
<name>{data.author || 'RSSHub'}</name>
|
||||
</author>
|
||||
{data.item?.map((item) => (
|
||||
<entry>
|
||||
<title>{item.title}</title>
|
||||
<content type="html" src={item.link}>{item.description}</content>
|
||||
<link href={item.link} />
|
||||
<id>{item.guid || item.link || item.title}</id>
|
||||
{item.pubDate && <published>{item.pubDate}</published>}
|
||||
{item.updated && <updated>{item.updated || item.pubDate}</updated>}
|
||||
{item.author && <author><name>{item.author}</name></author>}
|
||||
{typeof item.category === 'string' ? <category term={item.category}></category> : item.category?.map((c) => <category term={c}></category>)}
|
||||
{item.media &&
|
||||
Object.entries(item.media).map(([key, value]) => {
|
||||
const Tag = `media:${key}`;
|
||||
return <Tag {...value} />;
|
||||
})}
|
||||
</entry>
|
||||
))}
|
||||
</feed>
|
||||
);
|
||||
|
||||
export default RSS;
|
||||
@@ -1,60 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
|
||||
{{ if itunes_author || itunes_category || (item && item.some((i) => (i.itunes_item_image || i.itunes_duration))) }}
|
||||
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
|
||||
{{ /if }}
|
||||
{{ if item && item.some((i) => i.media) }}
|
||||
xmlns:media="http://search.yahoo.com/mrss/"
|
||||
{{ /if }}
|
||||
>
|
||||
<channel>
|
||||
<title><![CDATA[{{@ title || 'RSSHub' }}]]></title>
|
||||
<link>{{ link || 'https://docs.rsshub.app' }}</link>
|
||||
<atom:link href="{{ atomlink }}" rel="self" type="application/rss+xml" />
|
||||
<description><![CDATA[{{@ description || title }} - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)]]></description>
|
||||
<generator>RSSHub</generator>
|
||||
<webMaster>i@diygod.me (DIYgod)</webMaster>
|
||||
{{ if itunes_author }}<itunes:author>{{ itunes_author }}</itunes:author>{{ /if }}
|
||||
{{ if itunes_category }}<itunes:category text="{{ itunes_category }}"/>{{ /if }}
|
||||
{{ if itunes_author }}<itunes:explicit>{{ itunes_explicit || 'false' }}</itunes:explicit>{{ /if }}
|
||||
<language>{{ language || 'zh-cn' }}</language>
|
||||
{{ if image }}
|
||||
<image>
|
||||
<url>{{ image }}</url>
|
||||
<title><![CDATA[{{@ title || 'RSSHub' }}]]></title>
|
||||
<link>{{ link }}</link>
|
||||
</image>
|
||||
{{ /if }}
|
||||
<lastBuildDate>{{ lastBuildDate }}</lastBuildDate>
|
||||
<ttl>{{ ttl }}</ttl>
|
||||
{{ each item }}
|
||||
<item>
|
||||
<title><![CDATA[{{@ $value.title }}]]></title>
|
||||
<description><![CDATA[{{@ $value.description || $value.title }}]]></description>
|
||||
{{ if $value.pubDate }}<pubDate>{{ $value.pubDate }}</pubDate>{{ /if }}
|
||||
<guid isPermaLink="false">{{ $value.guid || $value.link || $value.title }}</guid>
|
||||
<link>{{ $value.link }}</link>
|
||||
{{ if $value.itunes_item_image }}<itunes:image href="{{ $value.itunes_item_image }}"/>{{ /if }}
|
||||
{{ if $value.enclosure_url }}<enclosure url="{{ $value.enclosure_url }}" {{ if $value.enclosure_length }}length="{{ $value.enclosure_length }}"{{ /if }} {{ if $value.enclosure_type }}type="{{ $value.enclosure_type }}"{{ /if }} />{{ /if }}
|
||||
{{ if $value.itunes_duration }}<itunes:duration>{{ $value.itunes_duration }}</itunes:duration> {{ /if }}
|
||||
{{ if $value.author }}<author><![CDATA[{{ $value.author }}]]></author>{{ /if }}
|
||||
{{ if typeof $value.category === 'string' }}
|
||||
<category>{{ $value.category }}</category>
|
||||
{{ else }}
|
||||
{{ each $value.category $c }}
|
||||
<category>{{ $c }}</category>
|
||||
{{ /each }}
|
||||
{{ /if }}
|
||||
{{ if $value.media }}
|
||||
{{ each $value.media $tag }}
|
||||
<media:{{ $index }}
|
||||
{{ each $tag $data }}
|
||||
{{ $index }}="{{ $data }}"
|
||||
{{ /each }}
|
||||
></media:{{ $index }}>
|
||||
{{ /each }}
|
||||
{{ /if }}
|
||||
</item>
|
||||
{{ /each }}
|
||||
</channel>
|
||||
</rss>
|
||||
53
lib/views/rss.tsx
Normal file
53
lib/views/rss.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import type { FC } from 'hono/jsx';
|
||||
import { Data } from '@/types';
|
||||
|
||||
const RSS: FC<{ data: Data }> = ({ data }) => {
|
||||
const hasItunes = data.itunes_author || data.itunes_category || (data.item && data.item.some((i) => i.itunes_item_image || i.itunes_duration));
|
||||
const hasMedia = data.item?.some((i) => i.media);
|
||||
|
||||
return (
|
||||
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes={hasItunes ? 'http://www.itunes.com/dtds/podcast-1.0.dtd' : undefined} xmlns:media={hasMedia ? 'http://search.yahoo.com/mrss/' : undefined} version="2.0">
|
||||
<channel>
|
||||
<title>{data.title || 'RSSHub'}</title>
|
||||
<link>{data.link || 'https://docs.rsshub.app'}</link>
|
||||
<atom:link href={data.atomlink} rel="self" type="application/rss+xml" />
|
||||
<description>{data.description || data.title} - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)</description>
|
||||
<generator>RSSHub</generator>
|
||||
<webMaster>i@diygod.me (DIYgod)</webMaster>
|
||||
{data.itunes_author && <itunes:author>{data.itunes_author}</itunes:author>}
|
||||
{data.itunes_category && <itunes:category text={data.itunes_category} />}
|
||||
{data.itunes_author && <itunes:explicit>{data.itunes_explicit || 'false'}</itunes:explicit>}
|
||||
<language>{data.language || 'en'}</language>
|
||||
{data.image && (
|
||||
<image>
|
||||
<url>{data.image}</url>
|
||||
<title>{data.title || 'RSSHub'}</title>
|
||||
<link>{data.link}</link>
|
||||
</image>
|
||||
)}
|
||||
<lastBuildDate>{data.lastBuildDate}</lastBuildDate>
|
||||
<ttl>{data.ttl}</ttl>
|
||||
{data.item?.map((item) => (
|
||||
<item>
|
||||
<title>{item.title}</title>
|
||||
<description>{item.description}</description>
|
||||
<link>{item.link}</link>
|
||||
<guid isPermaLink="false">{item.guid || item.link || item.title}</guid>
|
||||
{item.pubDate && <pubDate>{item.pubDate}</pubDate>}
|
||||
{item.author && <author>{item.author}</author>}
|
||||
{item.itunes_item_image && <itunes:image href={item.itunes_item_image} />}
|
||||
{item.enclosure_url && <enclosure url={item.enclosure_url} length={item.enclosure_length} type={item.enclosure_type} />}
|
||||
{item.itunes_duration && <itunes:duration>{item.itunes_duration}</itunes:duration>}
|
||||
{typeof item.category === 'string' ? <category>{item.category}</category> : item.category?.map((c) => <category>{c}</category>)}
|
||||
{item.media && Object.entries(item.media).map(([key, value]) => {
|
||||
const Tag = `media:${key}`;
|
||||
return <Tag {...value} />;
|
||||
})}
|
||||
</item>
|
||||
))}
|
||||
</channel>
|
||||
</rss>
|
||||
);
|
||||
};
|
||||
|
||||
export default RSS;
|
||||
@@ -71,7 +71,7 @@
|
||||
"git-rev-sync": "3.0.2",
|
||||
"googleapis": "134.0.0",
|
||||
"got": "11.8.6",
|
||||
"hono": "4.1.2",
|
||||
"hono": "4.1.3",
|
||||
"html-to-text": "9.0.5",
|
||||
"https-proxy-agent": "7.0.4",
|
||||
"iconv-lite": "0.6.3",
|
||||
|
||||
682
pnpm-lock.yaml
generated
682
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user