fix: rss widget post sorting (#1855)

This commit is contained in:
Manuel
2024-01-28 21:15:46 +01:00
committed by GitHub
parent 6fdf1dfaa8
commit ff21033b0c
3 changed files with 60 additions and 31 deletions

View File

@@ -20,6 +20,12 @@
},
"sortByPublishDateAscending": {
"label": "Sort by publish date (ascending)"
},
"sortPostsWithoutPublishDateToTheTop": {
"label": "Put posts without publish date to the top"
},
"maximumAmountOfPosts": {
"label": "Maximum amount of posts"
}
},
"card": {

View File

@@ -18,7 +18,7 @@ type CustomItem = {
'media:group'?: {
'media:description'?: string;
'media:thumbnail'?: string;
},
};
pubDate?: string;
};
@@ -44,10 +44,10 @@ const rssFeedResultObjectSchema = z
title: z.string(),
content: z.string(),
pubDate: z.date().optional(),
}),
})
),
}),
}),
})
);
export const rssRouter = createTRPCRouter({
@@ -57,7 +57,7 @@ export const rssRouter = createTRPCRouter({
widgetId: z.string().uuid(),
feedUrls: z.array(z.string()),
configName: z.string(),
}),
})
)
.output(z.array(rssFeedResultObjectSchema))
.query(async ({ input }) => {
@@ -80,13 +80,23 @@ export const rssRouter = createTRPCRouter({
return await Promise.all(
input.feedUrls.map(async (feedUrl) =>
getFeedUrl(feedUrl, rssWidget.properties.dangerousAllowSanitizedItemContent),
),
getFeedUrl(
feedUrl,
rssWidget.properties.dangerousAllowSanitizedItemContent,
rssWidget.properties.sortPostsWithoutPublishDateToTheTop,
rssWidget.properties.maximumAmountOfPosts
)
)
);
}),
});
const getFeedUrl = async (feedUrl: string, dangerousAllowSanitizedItemContent: boolean) => {
const getFeedUrl = async (
feedUrl: string,
dangerousAllowSanitizedItemContent: boolean,
sortPostsWithoutPubDateToTop: boolean,
maximumAmountOfPosts: number
) => {
Consola.info(`Requesting RSS feed at url ${feedUrl}`);
const stopWatch = new Stopwatch();
const feed = await parser.parseURL(feedUrl);
@@ -103,32 +113,34 @@ const getFeedUrl = async (feedUrl: string, dangerousAllowSanitizedItemContent: b
'media:group'?: {
'media:description'?: string;
'media:thumbnail'?: string;
}
};
categories: string[] | { _: string }[];
pubDate?: string;
}) => ({
...item,
categories: item.categories
?.map((category) => (typeof category === 'string' ? category : category._))
.filter((category: unknown): category is string => typeof category === 'string'),
title: item.title ? decode(item.title) : undefined,
content: processItemContent(
item['content:encoded'] ?? item.content ?? item['media:group']?.['media:description'],
dangerousAllowSanitizedItemContent,
),
enclosure: createEnclosure(item),
link: createLink(item),
pubDate: item.pubDate ? new Date(item.pubDate) : null,
}),
}) => {
Consola.info('item ' + item.title + ' has pub date ' + item.pubDate);
return {
...item,
categories: item.categories
?.map((category) => (typeof category === 'string' ? category : category._))
.filter((category: unknown): category is string => typeof category === 'string'),
title: item.title ? decode(item.title) : undefined,
content: processItemContent(
item['content:encoded'] ?? item.content ?? item['media:group']?.['media:description'],
dangerousAllowSanitizedItemContent
),
enclosure: createEnclosure(item),
link: createLink(item),
pubDate: item.pubDate ? new Date(item.pubDate) : null,
};
}
)
.sort((a: { pubDate: number }, b: { pubDate: number }) => {
if (!a.pubDate || !b.pubDate) {
return 0;
.sort((post1: { pubDate: number }, post2: { pubDate: number }) => {
if (!post1.pubDate || !post2.pubDate) {
return sortPostsWithoutPubDateToTop ? 1 : 0;
}
return a.pubDate - b.pubDate;
})
.slice(0, 20),
return post1.pubDate - post2.pubDate;
}),
};
return {
@@ -169,7 +181,7 @@ const processItemContent = (content: string, dangerousAllowSanitizedItemContent:
}
return encode(content, {
level: "html5"
level: 'html5',
});
};
@@ -195,7 +207,7 @@ const createEnclosure = (item: any) => {
if (item['media:group'] && item['media:group']['media:thumbnail']) {
// no clue why this janky parse is needed
return {
url: item['media:group']['media:thumbnail'][0].$.url
url: item['media:group']['media:thumbnail'][0].$.url,
};
}

View File

@@ -55,6 +55,17 @@ const definition = defineWidget({
type: 'switch',
defaultValue: true,
},
sortPostsWithoutPublishDateToTheTop: {
type: 'switch',
defaultValue: false
},
maximumAmountOfPosts: {
type: 'slider',
defaultValue: 20,
min: 1,
max: 350,
step: 1
}
},
gridstack: {
minWidth: 2,
@@ -127,7 +138,7 @@ function RssTile({ widget }: RssTileProps) {
<Stack h="100%">
<ScrollArea className="scroll-area-w100" w="100%" mt="sm" mb="sm">
<Stack w="100%" spacing="xs">
{orderedFeedItems.map((item: any, index: number) => (
{orderedFeedItems.slice(0, widget.properties.maximumAmountOfPosts).map((item: any, index: number) => (
<Card
key={index}
withBorder