diff --git a/apps/renderer/src/modules/discover/DiscoverFeedForm.tsx b/apps/renderer/src/modules/discover/DiscoverFeedForm.tsx index aae1a90163..10d3fbae86 100644 --- a/apps/renderer/src/modules/discover/DiscoverFeedForm.tsx +++ b/apps/renderer/src/modules/discover/DiscoverFeedForm.tsx @@ -22,6 +22,7 @@ import { SelectTrigger, SelectValue, } from "~/components/ui/select" +import { EllipsisHorizontalTextWithTooltip } from "~/components/ui/typography" import { nextFrame } from "~/lib/dom" import type { FeedViewType } from "~/lib/enum" import { @@ -84,16 +85,28 @@ const FeedDescription = ({ description }: { description?: string }) => { ) } +const routeParamsKeyPrefix = "route-params-" + +export type RouteParams = Record< + string, + { + description: string + default?: string + } +> + export const DiscoverFeedForm = ({ route, routePrefix, noDescription, submitButtonClassName, + routeParams, }: { route: RSSHubRoute routePrefix: string noDescription?: boolean submitButtonClassName?: string + routeParams?: RouteParams }) => { const { t } = useTranslation() const keys = useMemo( @@ -121,13 +134,22 @@ export const DiscoverFeedForm = ({ () => z.object({ ...Object.fromEntries( - keys.map((keyItem) => [ - keyItem.name, - keyItem.optional ? z.string().optional().nullable() : z.string().min(1), - ]), + keys + .map((keyItem) => [ + keyItem.name, + keyItem.optional ? z.string().optional().nullable() : z.string().min(1), + ]) + .concat( + routeParams + ? Object.entries(routeParams).map(([key]) => [ + `${routeParamsKeyPrefix}${key}`, + z.string(), + ]) + : [], + ), ), }), - [keys], + [keys, routeParams], ) const defaultValue = useMemo(() => { @@ -150,10 +172,30 @@ export const DiscoverFeedForm = ({ const { present, dismissAll } = useModalStack() const onSubmit = useCallback( - (data: Record) => { + (_data: Record) => { + const data = Object.fromEntries( + Object.entries(_data).filter(([key]) => !key.startsWith(routeParamsKeyPrefix)), + ) + try { - const fillRegexpPath = regexpPathToPath(route.path, data) + const routeParamsPath = encodeURIComponent( + Object.entries(_data) + .filter(([key, value]) => key.startsWith(routeParamsKeyPrefix) && value) + .map(([key, value]) => [key.slice(routeParamsKeyPrefix.length), value]) + .map(([key, value]) => `${key}=${value}`) + .join("&"), + ) + + const fillRegexpPath = regexpPathToPath( + routeParams && routeParamsPath + ? route.path.slice(0, route.path.indexOf("/:routeParams")) + : route.path, + data, + ) const url = `rsshub://${routePrefix}${fillRegexpPath}` + + const finalUrl = routeParams && routeParamsPath ? `${url}/${routeParamsPath}` : url + const defaultView = getViewFromRoute(route) || (getSidebarActiveView() as FeedViewType) present({ @@ -161,7 +203,7 @@ export const DiscoverFeedForm = ({ content: () => ( (null) @@ -259,6 +301,26 @@ export const DiscoverFeedForm = ({ ) })} + {routeParams && ( +
+ {Object.entries(routeParams).map(([key, value]) => ( + + {key} + + {!!value.description && ( + + + {value.description} + + + )} + + ))} +
+ )} {!noDescription && ( <> diff --git a/apps/renderer/src/modules/discover/transform-form.tsx b/apps/renderer/src/modules/discover/transform-form.tsx new file mode 100644 index 0000000000..1c1f9ae995 --- /dev/null +++ b/apps/renderer/src/modules/discover/transform-form.tsx @@ -0,0 +1,77 @@ +import { LoadingCircle } from "~/components/ui/loading" +import { useAuthQuery } from "~/hooks/common" +import { Queries } from "~/queries" + +import type { RouteParams } from "./DiscoverFeedForm" +import { DiscoverFeedForm } from "./DiscoverFeedForm" + +const transformRouteParams: RouteParams = { + title: { description: "The title of the RSS", default: "Extract from " }, + item: { description: "The HTML elements as item using CSS selector", default: "html" }, + itemTitle: { + description: "The HTML elements as title in item using CSS selector", + default: "item element", + }, + itemTitleAttr: { + description: "The attributes of title element as title", + default: "Element text", + }, + itemLink: { + description: "The HTML elements as link in item using CSS selector", + default: "item element", + }, + itemLinkAttr: { description: "The attributes of link element as link", default: "href" }, + itemDesc: { + description: "The HTML elements as description in item using CSS selector", + default: "item element", + }, + itemDescAttr: { + description: "The attributes of description element as description", + default: "Element html", + }, + itemPubDate: { + description: "The HTML elements as pubDate in item using CSS selector", + default: "item element", + }, + itemPubDateAttr: { + description: "The attributes of pubDate element as pubDate", + default: "Element html", + }, +} + +export function DiscoverTransform() { + const { data, isLoading } = useAuthQuery( + Queries.discover.rsshubNamespace({ + namespace: "rsshub", + }), + { + meta: { + persist: true, + }, + }, + ) + + if (isLoading) { + return ( + <div className="center mt-12 flex w-full flex-col gap-8"> + <LoadingCircle size="large" /> + </div> + ) + } + + return ( + <> + {data?.rsshub.routes && ( + <div className="w-[512px]"> + <DiscoverFeedForm + routePrefix="rsshub" + route={data?.rsshub.routes["/transform/html/:url/:routeParams"]} + routeParams={transformRouteParams} + noDescription + submitButtonClassName="justify-center" + /> + </div> + )} + </> + ) +} diff --git a/apps/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx b/apps/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx index 086be0b6ec..e07c996c6b 100644 --- a/apps/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx +++ b/apps/renderer/src/pages/(main)/(layer)/(subview)/discover/index.tsx @@ -8,6 +8,7 @@ import { DiscoverImport } from "~/modules/discover/import" import { DiscoverInboxList } from "~/modules/discover/inbox-list-form" import { Recommendations } from "~/modules/discover/recommendations" import { DiscoverRSS3 } from "~/modules/discover/rss3-form" +import { DiscoverTransform } from "~/modules/discover/transform-form" import { DiscoverUser } from "~/modules/discover/user-form" import { Trend } from "~/modules/trending" @@ -42,6 +43,10 @@ const tabs: { name: "words.user", value: "user", }, + { + name: "words.transform", + value: "transform", + }, { name: "words.import", value: "import", @@ -93,4 +98,5 @@ const TabComponent: Record<string, React.FC<{ type?: string }>> = { inbox: DiscoverInboxList, user: DiscoverUser, default: DiscoverForm, + transform: DiscoverTransform, } diff --git a/locales/app/en.json b/locales/app/en.json index a34d7e520f..d6969931d7 100644 --- a/locales/app/en.json +++ b/locales/app/en.json @@ -284,6 +284,7 @@ "words.search": "Search", "words.starred": "Starred", "words.title": "Title", + "words.transform": "Transform", "words.trending": "Trending", "words.undo": "Undo", "words.unread": "Unread",