mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-04 19:59:54 +08:00
fix(route): use GraphQL query in GitHub trending (#11188)
* fix(route): use GraphQL query in GitHub trending Uses GraphQL to get desired repository data instead of attempting to query it from the repository page. * docs: add `selfhost` attribute to GitHub trending
This commit is contained in:
@@ -1,59 +1,91 @@
|
||||
const config = require('@/config').value;
|
||||
const got = require('@/utils/got');
|
||||
const { art } = require('@/utils/render');
|
||||
const cheerio = require('cheerio');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
if (!config.github || !config.github.access_token) {
|
||||
throw 'GitHub trending RSS is disabled due to the lack of <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>';
|
||||
}
|
||||
const since = ctx.params.since;
|
||||
const language = ctx.params.language === 'any' ? '' : ctx.params.language;
|
||||
const spoken_language = ctx.params.spoken_language ?? '';
|
||||
const url = `https://github.com/trending/${encodeURIComponent(language)}?since=${since}&spoken_language_code=${spoken_language}`;
|
||||
|
||||
const response = await got({
|
||||
const trendingUrl = `https://github.com/trending/${encodeURIComponent(language)}?since=${since}&spoken_language_code=${spoken_language}`;
|
||||
const { data: trendingPage } = await got({
|
||||
method: 'get',
|
||||
url,
|
||||
url: trendingUrl,
|
||||
headers: {
|
||||
Referer: url,
|
||||
Referer: trendingUrl,
|
||||
},
|
||||
});
|
||||
const $ = cheerio.load(trendingPage);
|
||||
|
||||
const articles = $('article');
|
||||
const trendingRepos = articles
|
||||
.map((_, item) => {
|
||||
const [owner, name] = $(item).find('h1').text().split('/');
|
||||
return {
|
||||
name: name.trim(),
|
||||
owner: owner.trim(),
|
||||
};
|
||||
})
|
||||
.get();
|
||||
|
||||
const { data: repoData } = await got({
|
||||
method: 'post',
|
||||
url: 'https://api.github.com/graphql',
|
||||
headers: {
|
||||
Authorization: `bearer ${config.github.access_token}`,
|
||||
},
|
||||
json: {
|
||||
query: `
|
||||
query {
|
||||
${trendingRepos
|
||||
.map(
|
||||
(repo, index) => `
|
||||
_${index}: repository(owner: "${repo.owner}", name: "${repo.name}") {
|
||||
...RepositoryFragment
|
||||
}
|
||||
`
|
||||
)
|
||||
.join('\n')}
|
||||
}
|
||||
|
||||
fragment RepositoryFragment on Repository {
|
||||
description
|
||||
forkCount
|
||||
nameWithOwner
|
||||
openGraphImageUrl
|
||||
primaryLanguage {
|
||||
name
|
||||
}
|
||||
stargazerCount
|
||||
}
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
const data = response.data;
|
||||
|
||||
const $ = cheerio.load(data);
|
||||
const list = $('article');
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((_, item) => {
|
||||
item = $(item);
|
||||
const endpoint = item.find('h1 a').attr('href');
|
||||
const link = `https://github.com${endpoint}`;
|
||||
return ctx.cache.tryGet(`github:trending:${endpoint}`, async () => {
|
||||
const response = await got(link);
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
const cover = $('meta[property="og:image"]');
|
||||
|
||||
const single = {
|
||||
title: item.find('h1').text(),
|
||||
author: item.find('h1').text().split('/')[0].trim(),
|
||||
description: art(path.join(__dirname, 'templates/trending-description.art'), {
|
||||
cover: cover.attr('content'),
|
||||
desc: item.find('p').text(),
|
||||
lang: item.find('span[itemprop="programmingLanguage"]').text() || 'Unknown',
|
||||
stars: item.find('.Link--muted').eq(0).text().trim(),
|
||||
forks: item.find('.Link--muted').eq(1).text().trim(),
|
||||
}),
|
||||
link,
|
||||
};
|
||||
|
||||
return single;
|
||||
});
|
||||
})
|
||||
);
|
||||
const repos = Object.values(repoData.data).map((repo) => {
|
||||
const found = trendingRepos.find((r) => `${r.owner}/${r.name}` === repo.nameWithOwner);
|
||||
return { ...found, ...repo };
|
||||
});
|
||||
|
||||
ctx.state.data = {
|
||||
title: $('title').text(),
|
||||
link: url,
|
||||
item: items,
|
||||
link: trendingUrl,
|
||||
item: repos.map((r) => ({
|
||||
title: r.nameWithOwner,
|
||||
author: r.owner,
|
||||
description: art(path.join(__dirname, 'templates/trending-description.art'), {
|
||||
cover: r.openGraphImageUrl,
|
||||
desc: r.description,
|
||||
forks: r.forkCount,
|
||||
lang: r.primaryLanguage?.name || 'Unknown',
|
||||
stars: r.stargazerCount,
|
||||
}),
|
||||
link: `https://github.com/${r.nameWithOwner}`,
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user