Skip to content

Commit c21c82f

Browse files
TonyRLCopilot
andauthored
feat(route/digg): add digg community posts (#20900)
* feat(route/digg): add digg community posts * Update lib/routes/digg/community.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 3ecf9ee commit c21c82f

File tree

3 files changed

+556
-0
lines changed

3 files changed

+556
-0
lines changed

lib/routes/digg/community.tsx

Lines changed: 396 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,396 @@
1+
import { renderToString } from 'hono/jsx/dom/server';
2+
3+
import type { Route } from '@/types';
4+
import cache from '@/utils/cache';
5+
import ofetch from '@/utils/ofetch';
6+
import { parseDate } from '@/utils/parse-date';
7+
8+
import type { PostNode } from './types';
9+
10+
export const route: Route = {
11+
path: '/community/:community',
12+
categories: ['social-media'],
13+
example: '/digg/community/askdigg',
14+
parameters: {
15+
community: 'Community slug, can be found in the URL',
16+
},
17+
features: {
18+
requireConfig: false,
19+
requirePuppeteer: false,
20+
antiCrawler: false,
21+
supportBT: false,
22+
supportPodcast: false,
23+
supportScihub: false,
24+
},
25+
radar: [
26+
{
27+
source: ['digg.com/:community'],
28+
},
29+
],
30+
name: 'Community Posts',
31+
maintainers: ['TonyRL'],
32+
handler,
33+
url: 'digg.com/',
34+
};
35+
36+
const baseUrl = 'https://digg.com';
37+
const graphqlUrl = 'https://apineapple-prod.digg.com/graphql';
38+
39+
const DiggDescription = ({ node }) => {
40+
if (!node) {
41+
return null;
42+
}
43+
44+
const children = Array.isArray(node.content) ? node.content : [];
45+
46+
switch (node.type) {
47+
case 'bulletList':
48+
return (
49+
<ul>
50+
{children.map((element, index) => (
51+
<DiggDescription node={element} key={index} />
52+
))}
53+
</ul>
54+
);
55+
case 'listItem':
56+
return (
57+
<li>
58+
{children.map((element, index) => (
59+
<DiggDescription node={element} key={index} />
60+
))}
61+
</li>
62+
);
63+
64+
case 'diggImagesBlock':
65+
if (node.attrs && Array.isArray(node.attrs.images)) {
66+
return (
67+
<div>
68+
{node.attrs.images.map((img: any, index: number) => (
69+
<img src={img.url} alt="" width={img.width} height={img.height} key={index} />
70+
))}
71+
</div>
72+
);
73+
}
74+
return null;
75+
76+
case 'diggLinkBlock':
77+
return (
78+
<>
79+
<a href={node.attrs.url}>
80+
{node.attrs.title || node.attrs.url}
81+
<br />
82+
{node.attrs.description}
83+
</a>
84+
{node.attrs.tldr}
85+
</>
86+
);
87+
88+
case 'diggTextBlock':
89+
case 'doc':
90+
return (
91+
<>
92+
{children.map((element, index) => (
93+
<DiggDescription node={element} key={index} />
94+
))}
95+
</>
96+
);
97+
98+
case 'diggTitleBlock':
99+
return null;
100+
101+
case 'hardBreak':
102+
return <br />;
103+
104+
case 'mention':
105+
return <a href={`${baseUrl}/${node.attrs.label}`}>/{node.attrs.label}</a>;
106+
107+
case 'paragraph':
108+
if (children.length === 0) {
109+
return null;
110+
}
111+
return (
112+
<p>
113+
{children.map((element, index) => (
114+
<DiggDescription node={element} key={index} />
115+
))}
116+
<br />
117+
</p>
118+
);
119+
120+
case 'text':
121+
return node.text || '';
122+
123+
default:
124+
throw new Error(`Unknown node type: ${node.type}`);
125+
}
126+
};
127+
128+
async function handler(ctx) {
129+
const { community } = ctx.req.param();
130+
const limit = Number.parseInt(ctx.req.query('limit') ?? 30, 10);
131+
132+
const communityData = await cache.tryGet(`digg:community:${community}`, async () => {
133+
const {
134+
data: { community: communityData },
135+
} = await ofetch(graphqlUrl, {
136+
method: 'POST',
137+
body: {
138+
query: `query CommunityQuery($id: ID, $slug: String) {
139+
community(where: { _id_EQ: $id, slug_EQ: $slug }) {
140+
...CommunityFragment
141+
topContributors {
142+
account {
143+
_id
144+
avatarUrl
145+
avatarImage {
146+
...ImageFragment
147+
}
148+
username
149+
}
150+
score
151+
}
152+
topGemFinders {
153+
account {
154+
_id
155+
avatarUrl
156+
avatarImage {
157+
...ImageFragment
158+
}
159+
username
160+
}
161+
score
162+
}
163+
}
164+
}
165+
fragment AuthorFragment on Account {
166+
_id
167+
username
168+
avatarUrl
169+
avatarImage {
170+
...ImageFragment
171+
}
172+
badges {
173+
name
174+
iconUrl
175+
}
176+
blockStatus
177+
roles {
178+
name
179+
iconUrl
180+
}
181+
}
182+
fragment CommunityFragment on Community {
183+
_id
184+
name
185+
slug
186+
description
187+
iconUrl
188+
guidelinesPM
189+
descriptionPM
190+
iconImage {
191+
...ImageFragment
192+
}
193+
bannerUrl
194+
bannerDesktopImage {
195+
...ImageFragment
196+
}
197+
bannerMobileImage {
198+
...ImageFragment
199+
}
200+
founder {
201+
...AuthorFragment
202+
bio
203+
}
204+
manager {
205+
...AuthorFragment
206+
}
207+
memberCount
208+
postCount
209+
isJoinedByAccount
210+
isPinnedByAccount
211+
isJoinedByDefault
212+
createdDate
213+
editedDate
214+
deletedDate
215+
}
216+
fragment ImageFragment on Image {
217+
alt
218+
height
219+
width
220+
url
221+
blurhash
222+
}`,
223+
variables: { slug: community },
224+
},
225+
});
226+
227+
return communityData;
228+
});
229+
230+
const {
231+
data: { posts },
232+
} = await ofetch(graphqlUrl, {
233+
method: 'POST',
234+
body: {
235+
query: `query PostsQuery(
236+
$first: Int
237+
$after: String
238+
$where: PostWhere
239+
$sort: PostSort
240+
) {
241+
posts(first: $first, after: $after, where: $where, sort: $sort) {
242+
edges {
243+
node {
244+
...PostsNodeFragment
245+
}
246+
}
247+
pageInfo {
248+
...PageInfoFragment
249+
}
250+
}
251+
}
252+
fragment AuthorFragment on Account {
253+
_id
254+
username
255+
avatarUrl
256+
avatarImage {
257+
...ImageFragment
258+
}
259+
badges {
260+
name
261+
iconUrl
262+
}
263+
blockStatus
264+
roles {
265+
name
266+
iconUrl
267+
}
268+
}
269+
fragment CommunityFragment on Community {
270+
_id
271+
name
272+
slug
273+
description
274+
iconUrl
275+
guidelinesPM
276+
descriptionPM
277+
iconImage {
278+
...ImageFragment
279+
}
280+
bannerUrl
281+
bannerDesktopImage {
282+
...ImageFragment
283+
}
284+
bannerMobileImage {
285+
...ImageFragment
286+
}
287+
founder {
288+
...AuthorFragment
289+
bio
290+
}
291+
manager {
292+
...AuthorFragment
293+
}
294+
memberCount
295+
postCount
296+
isJoinedByAccount
297+
isPinnedByAccount
298+
isJoinedByDefault
299+
createdDate
300+
editedDate
301+
deletedDate
302+
}
303+
fragment ImageFragment on Image {
304+
alt
305+
height
306+
width
307+
url
308+
blurhash
309+
}
310+
fragment ModerationReasonFragment on ModerationRemovalReason {
311+
id
312+
key
313+
description
314+
message
315+
type
316+
createdDate
317+
editedDate
318+
deletedDate
319+
}
320+
fragment PageInfoFragment on PageInfo {
321+
endCursor
322+
hasNextPage
323+
hasPreviousPage
324+
startCursor
325+
}
326+
fragment PostsNodeFragment on Post {
327+
_id
328+
title
329+
isSavedByAccount
330+
moderationStatus
331+
isDuggByAccount
332+
voteDirectionByAccount
333+
upvoteCount
334+
downvoteCount
335+
score
336+
reportByAccount
337+
slug
338+
type
339+
externalContent {
340+
url
341+
headline
342+
subHeadline
343+
imageUrl
344+
iconUrl
345+
}
346+
commentCount
347+
shareCount
348+
textPreview
349+
contextCards {
350+
tldr {
351+
text
352+
}
353+
}
354+
community {
355+
...CommunityFragment
356+
}
357+
attachments {
358+
__typename
359+
... on Image {
360+
...ImageFragment
361+
}
362+
}
363+
author {
364+
...AuthorFragment
365+
}
366+
createdDate
367+
editedDate
368+
deletedDate
369+
nsfw
370+
text
371+
pm
372+
moderatedDate
373+
moderationReason {
374+
...ModerationReasonFragment
375+
}
376+
}`,
377+
variables: { first: limit, where: { community: { slug_EQ: community } }, sort: 'RECENT' },
378+
},
379+
});
380+
381+
const items = posts.edges.map(({ node }: { node: PostNode }) => ({
382+
title: node.title,
383+
description: renderToString(<DiggDescription node={node.pm} />),
384+
link: `${baseUrl}/${node._id.replaceAll('-', '/')}/${node.slug}`,
385+
pubDate: parseDate(node.createdDate),
386+
author: node.author.username,
387+
}));
388+
389+
return {
390+
title: `${communityData.name} Community | Digg | Digg`,
391+
description: communityData.description,
392+
image: communityData.iconUrl,
393+
link: `${baseUrl}/${community}`,
394+
item: items,
395+
};
396+
}

0 commit comments

Comments
 (0)