feat(route): daily.dev user (#15403)
This commit is contained in:
parent
3cb4b741ae
commit
715bad0663
|
|
@ -59,21 +59,10 @@ const graphqlQuery = {
|
|||
|
||||
export const route: Route = {
|
||||
path: '/discussed',
|
||||
categories: ['social-media'],
|
||||
example: '/daily/discussed',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['daily.dev/popular'],
|
||||
target: '',
|
||||
},
|
||||
],
|
||||
name: 'Most Discussed',
|
||||
|
|
|
|||
|
|
@ -69,13 +69,13 @@ const graphqlQuery = {
|
|||
|
||||
export const route: Route = {
|
||||
path: '/',
|
||||
example: '/daily',
|
||||
radar: [
|
||||
{
|
||||
source: ['daily.dev/popular'],
|
||||
target: '',
|
||||
},
|
||||
],
|
||||
name: 'Unknown',
|
||||
name: 'Popular',
|
||||
maintainers: ['Rjnishant530'],
|
||||
handler,
|
||||
url: 'daily.dev/popular',
|
||||
|
|
|
|||
|
|
@ -3,4 +3,5 @@ import type { Namespace } from '@/types';
|
|||
export const namespace: Namespace = {
|
||||
name: 'Daily.dev',
|
||||
url: 'daily.dev',
|
||||
categories: ['social-media'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
{{ if image }}
|
||||
<img src="{{ image }}"><br>
|
||||
{{ /if }}
|
||||
|
||||
{{ if content }}
|
||||
{{@ content }}
|
||||
{{ /if }}
|
||||
|
|
@ -16,7 +16,7 @@ const query = `
|
|||
...FeedPostConnection
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fragment FeedPostConnection on PostConnection {
|
||||
edges {
|
||||
node {
|
||||
|
|
@ -24,11 +24,11 @@ const query = `
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fragment FeedPost on Post {
|
||||
...SharedPostInfo
|
||||
}
|
||||
|
||||
|
||||
fragment SharedPostInfo on Post {
|
||||
id
|
||||
title
|
||||
|
|
@ -44,7 +44,7 @@ const query = `
|
|||
}
|
||||
tags
|
||||
}
|
||||
|
||||
|
||||
fragment UserShortInfo on User {
|
||||
id
|
||||
name
|
||||
|
|
@ -53,7 +53,7 @@ const query = `
|
|||
username
|
||||
bio
|
||||
}
|
||||
|
||||
|
||||
`;
|
||||
|
||||
const graphqlQuery = {
|
||||
|
|
@ -63,21 +63,10 @@ const graphqlQuery = {
|
|||
|
||||
export const route: Route = {
|
||||
path: '/upvoted',
|
||||
categories: ['social-media'],
|
||||
example: '/daily/upvoted',
|
||||
parameters: {},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['daily.dev/popular'],
|
||||
target: '',
|
||||
},
|
||||
],
|
||||
name: 'Most upvoted',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
import { Route } from '@/types';
|
||||
import { baseUrl, getBuildId, getData } from './utils';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import cache from '@/utils/cache';
|
||||
import { config } from '@/config';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { art } from '@/utils/render';
|
||||
import path from 'path';
|
||||
import { getCurrentPath } from '@/utils/helpers';
|
||||
const __dirname = getCurrentPath(import.meta.url);
|
||||
|
||||
const userPostQuery = `
|
||||
query AuthorFeed(
|
||||
$loggedIn: Boolean! = false
|
||||
$userId: ID!
|
||||
$after: String
|
||||
$first: Int
|
||||
$supportedTypes: [String!] = [
|
||||
"article"
|
||||
"share"
|
||||
"freeform"
|
||||
"video:youtube"
|
||||
"collection"
|
||||
]
|
||||
) {
|
||||
page: authorFeed(
|
||||
author: $userId
|
||||
after: $after
|
||||
first: $first
|
||||
ranking: TIME
|
||||
supportedTypes: $supportedTypes
|
||||
) {
|
||||
...FeedPostConnection
|
||||
}
|
||||
}
|
||||
fragment FeedPostConnection on PostConnection {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
node {
|
||||
...FeedPost
|
||||
contentHtml
|
||||
...UserPost @include(if: $loggedIn)
|
||||
}
|
||||
}
|
||||
}
|
||||
fragment FeedPost on Post {
|
||||
...SharedPostInfo
|
||||
sharedPost {
|
||||
...SharedPostInfo
|
||||
}
|
||||
trending
|
||||
feedMeta
|
||||
collectionSources {
|
||||
handle
|
||||
image
|
||||
}
|
||||
numCollectionSources
|
||||
updatedAt
|
||||
slug
|
||||
}
|
||||
fragment SharedPostInfo on Post {
|
||||
id
|
||||
title
|
||||
titleHtml
|
||||
image
|
||||
readTime
|
||||
permalink
|
||||
commentsPermalink
|
||||
summary
|
||||
createdAt
|
||||
private
|
||||
upvoted
|
||||
commented
|
||||
bookmarked
|
||||
views
|
||||
numUpvotes
|
||||
numComments
|
||||
videoId
|
||||
scout {
|
||||
...UserShortInfo
|
||||
}
|
||||
author {
|
||||
...UserShortInfo
|
||||
}
|
||||
type
|
||||
tags
|
||||
source {
|
||||
...SourceBaseInfo
|
||||
}
|
||||
downvoted
|
||||
flags {
|
||||
promoteToPublic
|
||||
}
|
||||
userState {
|
||||
vote
|
||||
flags {
|
||||
feedbackDismiss
|
||||
}
|
||||
}
|
||||
slug
|
||||
}
|
||||
fragment SourceBaseInfo on Source {
|
||||
id
|
||||
active
|
||||
handle
|
||||
name
|
||||
permalink
|
||||
public
|
||||
type
|
||||
description
|
||||
image
|
||||
membersCount
|
||||
privilegedMembers {
|
||||
user {
|
||||
id
|
||||
}
|
||||
role
|
||||
}
|
||||
currentMember {
|
||||
...CurrentMember
|
||||
}
|
||||
memberPostingRole
|
||||
memberInviteRole
|
||||
}
|
||||
fragment CurrentMember on SourceMember {
|
||||
user {
|
||||
id
|
||||
}
|
||||
permissions
|
||||
role
|
||||
referralToken
|
||||
flags {
|
||||
hideFeedPosts
|
||||
collapsePinnedPosts
|
||||
}
|
||||
}
|
||||
fragment UserShortInfo on User {
|
||||
id
|
||||
name
|
||||
image
|
||||
permalink
|
||||
username
|
||||
bio
|
||||
createdAt
|
||||
reputation
|
||||
}
|
||||
fragment UserPost on Post {
|
||||
read
|
||||
upvoted
|
||||
commented
|
||||
bookmarked
|
||||
downvoted
|
||||
}`;
|
||||
|
||||
const render = (data) => art(path.join(__dirname, 'templates/posts.art'), data);
|
||||
|
||||
export const route: Route = {
|
||||
path: '/user/:userId',
|
||||
example: '/daily/user/kramer',
|
||||
radar: [
|
||||
{
|
||||
source: ['daily.dev/:userId/posts', 'daily.dev/:userId'],
|
||||
},
|
||||
],
|
||||
name: 'User Posts',
|
||||
maintainers: ['TonyRL'],
|
||||
handler,
|
||||
url: 'daily.dev',
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const userId = ctx.req.param('userId');
|
||||
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 7;
|
||||
|
||||
const buildId = await getBuildId();
|
||||
|
||||
const userData = await cache.tryGet(`daily:user:${userId}`, async () => {
|
||||
const resposne = await ofetch(`${baseUrl}/_next/data/${buildId}/en/${userId}.json`, {
|
||||
query: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
return resposne.pageProps;
|
||||
});
|
||||
const user = (userData as any).user;
|
||||
|
||||
const items = await cache.tryGet(
|
||||
`daily:user:${userId}:posts`,
|
||||
async () => {
|
||||
const edges = await getData({
|
||||
query: userPostQuery,
|
||||
variables: {
|
||||
userId: user.id,
|
||||
first: limit,
|
||||
loggedIn: false,
|
||||
},
|
||||
});
|
||||
return edges.map(({ node }) => ({
|
||||
title: node.title,
|
||||
description: render({
|
||||
image: node.image,
|
||||
content: node.contentHtml?.replaceAll('\n', '<br>') ?? node.summary,
|
||||
}),
|
||||
link: node.permalink,
|
||||
author: node.author?.name,
|
||||
category: node.tags,
|
||||
pubDate: parseDate(node.createdAt),
|
||||
}));
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
);
|
||||
|
||||
return {
|
||||
title: `${user.name} | daily.dev`,
|
||||
description: user.bio,
|
||||
link: `${baseUrl}/${userId}/posts`,
|
||||
item: items,
|
||||
image: user.image,
|
||||
logo: user.image,
|
||||
icon: user.image,
|
||||
language: 'en-us',
|
||||
};
|
||||
}
|
||||
|
|
@ -1,19 +1,34 @@
|
|||
import dayjs from 'dayjs';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import cache from '@/utils/cache';
|
||||
import { config } from '@/config';
|
||||
|
||||
const getData = async (graphqlQuery) =>
|
||||
(
|
||||
await got
|
||||
.post('https://app.daily.dev/api/graphql', {
|
||||
json: graphqlQuery,
|
||||
})
|
||||
.json()
|
||||
).data.page.edges;
|
||||
const baseUrl = 'https://app.daily.dev';
|
||||
|
||||
const getBuildId = () =>
|
||||
cache.tryGet(
|
||||
'daily:buildId',
|
||||
async () => {
|
||||
const response = await ofetch(`${baseUrl}/onboarding`);
|
||||
const buildId = response.match(/"buildId":"(.*?)"/)[1];
|
||||
return buildId;
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
);
|
||||
|
||||
const getData = async (graphqlQuery) => {
|
||||
const response = await ofetch(`${baseUrl}/api/graphql`, {
|
||||
method: 'POST',
|
||||
body: graphqlQuery,
|
||||
});
|
||||
return response.data.page.edges;
|
||||
};
|
||||
|
||||
const getList = (data) =>
|
||||
data.map((value) => {
|
||||
const { id, title, image, permalink, summary, createdAt, numUpvotes, author, tags, numComments } = value.node;
|
||||
const pubDate = dayjs(createdAt);
|
||||
const pubDate = parseDate(createdAt);
|
||||
return {
|
||||
id,
|
||||
title,
|
||||
|
|
@ -30,10 +45,12 @@ const getList = (data) =>
|
|||
|
||||
const getRedirectedLink = (data) =>
|
||||
Promise.all(
|
||||
data.map(async (v) => {
|
||||
const resp = await got(v.link);
|
||||
return { ...v, link: resp.headers.link.split(/[<>]/g)[1] };
|
||||
})
|
||||
data.map((v) =>
|
||||
cache.tryGet(v.link, async () => {
|
||||
const resp = await ofetch.raw(v.link);
|
||||
return { ...v, link: resp.headers.get('location') };
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
export { getData, getList, getRedirectedLink };
|
||||
export { baseUrl, getBuildId, getData, getList, getRedirectedLink };
|
||||
|
|
|
|||
Loading…
Reference in New Issue