diff --git a/lib/v2/github/maintainer.js b/lib/v2/github/maintainer.js index 0cdc6b716f..d96156e87e 100644 --- a/lib/v2/github/maintainer.js +++ b/lib/v2/github/maintainer.js @@ -7,6 +7,7 @@ module.exports = { '/issue/:user/:repo/:state?/:labels?': ['HenryQW', 'AndreyMZ'], '/notifications': ['zhzy0077'], '/pull/:user/:repo/:state?': ['hashman', 'TonyRL'], + '/pulse/:user/:repo/:period?': ['jameschensmith'], '/repos/:user': ['DIYgod'], '/search/:query/:sort?/:order?': ['LogicJake'], '/starred_repos/:user': ['LanceZhu'], diff --git a/lib/v2/github/pulse.js b/lib/v2/github/pulse.js new file mode 100644 index 0000000000..7cdc16d63f --- /dev/null +++ b/lib/v2/github/pulse.js @@ -0,0 +1,87 @@ +const cheerio = require('cheerio'); +const path = require('path'); +const got = require('@/utils/got'); +const md5 = require('@/utils/md5'); +const { parseDate } = require('@/utils/parse-date'); +const { art } = require('@/utils/render'); + +module.exports = async (ctx) => { + const { user, repo, period } = ctx.params; + + const periods = ['daily', 'halfweekly', 'weekly', 'monthly']; + const pulsePeriod = periods.includes(period) ? period : periods[2]; + + const link = `https://github.com/${user}/${repo}/pulse/${pulsePeriod}`; + const { data: pulsePage } = await got(link); + const $ = cheerio.load(pulsePage); + + const $mainSections = $('main .Layout-main').children(); + + const $subheading = $mainSections.eq(0); + const [periodFrom, periodTo] = $subheading.find('h2').text().split('–'); + + const $overview = $mainSections.eq(1); + const overviewItems = $overview + .find('ul ul li') + .map((_, el) => $(el).text()) + .toArray(); + + const $commitActivity = $mainSections.eq(2); + let commitActivity; + const $contributionData = $commitActivity.find('.js-pulse-contribution-data'); + if ($contributionData.length) { + const summaryUrl = $contributionData.attr('data-pulse-diffstat-summary-url'); + commitActivity = (await got(`https://github.com${summaryUrl}`)).data; + } else { + commitActivity = $commitActivity.text(); + } + + const $githubActivity = $mainSections.eq(3); + let githubActivity; + const $sections = $githubActivity.find('h3'); + if ($sections.length) { + githubActivity = $sections + .map((_, section) => { + const $section = $(section); + const $sectionSiblings = $section.nextUntil('h3'); + const $paragraph = $section.nextUntil('ul'); + const $list = $sectionSiblings.last(); + return { + heading: $section.text(), + paragraph: $paragraph.length > 0 ? $paragraph.text() : undefined, + items: $list + .children() + .map((_, item) => { + const $item = $(item); + const $link = $item.find('a'); + const $details = $item.find('p'); + const $relativeTime = $details.find('relative-time'); + $relativeTime.replaceWith($relativeTime.attr('datetime')); + return { + link: { text: $link.text(), url: $link.attr('href') }, + details: $details.text(), + }; + }) + .toArray(), + }; + }) + .toArray(); + } + + ctx.state.data = { + title: `${user}/${repo} ${pulsePeriod} Pulse`, + link, + item: [ + { + guid: md5(`${user}${repo}${period}${periodFrom}${periodTo}`), + title: `${periodFrom} - ${periodTo}`, + description: art(path.join(__dirname, 'templates/pulse-description.art'), { + overviewItems, + commitActivity, + githubActivity, + }), + pubDate: parseDate(periodTo), + }, + ], + }; +}; diff --git a/lib/v2/github/radar.js b/lib/v2/github/radar.js index 8fb37f5f0a..b844bda5bf 100644 --- a/lib/v2/github/radar.js +++ b/lib/v2/github/radar.js @@ -44,6 +44,12 @@ module.exports = { source: ['/:user/:repo/pulls', '/:user/:repo/pulls/:id', '/:user/:repo'], target: '/github/pull/:user/:repo', }, + { + title: 'Pulse', + docs: 'https://docs.rsshub.app/routes/programming#github', + source: ['/:user/:repo/pulse', '/:user/:repo/pulse/:period'], + target: '/github/pulse/:user/:repo/:period?', + }, { title: '用户仓库', docs: 'https://docs.rsshub.app/routes/programming#github', diff --git a/lib/v2/github/router.js b/lib/v2/github/router.js index 7b8f52b4a2..dcd838658f 100644 --- a/lib/v2/github/router.js +++ b/lib/v2/github/router.js @@ -8,6 +8,7 @@ module.exports = function (router) { router.get('/issue/:user/:repo/:state?/:labels?', require('./issue')); router.get('/notifications', require('./notifications')); router.get('/pull/:user/:repo/:state?/:labels?', require('./pulls')); + router.get('/pulse/:user/:repo/:period?', require('./pulse')); router.get('/repos/:user', require('./repos')); router.get('/search/:query/:sort?/:order?', require('./search')); router.get('/starred_repos/:user', require('./starred_repos')); diff --git a/lib/v2/github/templates/pulse-description.art b/lib/v2/github/templates/pulse-description.art new file mode 100644 index 0000000000..d5580e7dd9 --- /dev/null +++ b/lib/v2/github/templates/pulse-description.art @@ -0,0 +1,24 @@ +
{{activity.paragraph}}
+ {{/if}} +{{item.details}}
+