{
+ const { appid = '958260', language = 'english' } = ctx.req.param();
+ const limitQuery = ctx.req.query('limit');
+ const limit = limitQuery ? Number.parseInt(limitQuery, 10) : 100;
+
+ const rootUrl = 'https://steamcommunity.com';
+ const apiRootUrl = 'https://store.steampowered.com';
+ const cdnRootUrl = 'https://clan.steamstatic.com/images';
+ const apiUrl = new URL('events/ajaxgetpartnereventspageable/', apiRootUrl).href;
+
+ const { data: response } = await got(apiUrl, {
+ searchParams: {
+ clan_accountid: 0,
+ appid,
+ offset: 0,
+ count: limit,
+ l: language,
+ },
+ });
+
+ const items: DataItem[] = response.events.slice(0, limit).map((item): DataItem => {
+ const title = item.event_name;
+ const description = `${bbobHTML(
+ item.announcement_body.body
+ .replaceAll('{STEAM_CLAN_IMAGE}', cdnRootUrl)
+ .replaceAll('[olist]', '[list=1]')
+ .replaceAll('[/olist]', '[/list]')
+ .replaceAll(/\[previewyoutube=([A-Za-z0-9_-]+).*?\/previewyoutube\]/g, ''),
+ [customPreset(), swapLinebreak]
+ )}
`;
+ const jsondata = JSON.parse(item.jsondata);
+ const titleImage = jsondata.localized_title_image ? jsondata.localized_capsule_image[0] : null;
+ const capsuleImage = jsondata.localized_capsule_image ? jsondata.localized_capsule_image[0] : null;
+
+ return {
+ title,
+ description,
+ pubDate: parseDate(item.announcement_body.posttime, 'X'),
+ link: new URL(`games/${appid}/announcements/detail/${item.announcement_body.gid}`, rootUrl).href,
+ category: item.announcement_body.tags,
+ content: {
+ html: description,
+ text: item.announcement_body.body,
+ },
+ updated: parseDate(item.announcement_body.updatetime, 'X'),
+ image: new URL(`images/${item.announcement_body.clanid}/${capsuleImage}`, cdnRootUrl).href,
+ banner: new URL(`images/${item.announcement_body.clanid}/${titleImage}`, cdnRootUrl).href,
+ };
+ });
+
+ return {
+ title: `App ${appid} News`,
+ link: new URL(`app/${appid}/allnews/`, rootUrl).href,
+ item: items,
+ language: langMap[language] || null,
+ };
+}
+
+const swapLinebreak = (tree: BBobCoreTagNodeTree) =>
+ tree.walk((node) => {
+ if (typeof node === 'string' && node === '\n') {
+ return {
+ tag: 'br',
+ content: null,
+ };
+ }
+ return node;
+ });
+
+const customPreset: PresetFactory = presetHTML5.extend((tags) => ({
+ ...tags,
+ url: (node) => ({
+ tag: 'a',
+ attrs: {
+ href: Object.keys(node.attrs as Record)[0],
+ rel: 'noopener',
+ target: '_blank',
+ },
+ content: node.content,
+ }),
+ video: (node, { render }) => ({
+ tag: 'video',
+ attrs: {
+ controls: '',
+ preload: 'metadata',
+ poster: node.attrs?.poster,
+ },
+ content: render(
+ Object.entries({
+ webm: 'video/webm',
+ mp4: 'video/mp4',
+ }).map(([key, type]) => ({
+ tag: 'source',
+ attrs: {
+ src: node.attrs?.[key],
+ type,
+ },
+ }))
+ ),
+ }),
+}));