diff --git a/docs/programming.md b/docs/programming.md
index 452abe75c1..5abbea528a 100644
--- a/docs/programming.md
+++ b/docs/programming.md
@@ -311,6 +311,26 @@ GitHub 官方也提供了一些 RSS:
+## HelloGitHub
+
+### 文章列表
+
+
+
+### 编程语言排行榜
+
+
+
+| 编程语言排行 | 数据库排行 | 服务端语言排行 |
+| ------ | ----- | --------- |
+| tiobe | db | webserver |
+
+
+
+### 月刊
+
+
+
## Hex-Rays
### Hex-Rays News
diff --git a/lib/v2/hellogithub/article.js b/lib/v2/hellogithub/article.js
new file mode 100644
index 0000000000..ea38bc9a68
--- /dev/null
+++ b/lib/v2/hellogithub/article.js
@@ -0,0 +1,47 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+const timezone = require('@/utils/timezone');
+
+module.exports = async (ctx) => {
+ const rootUrl = 'https://hellogithub.com';
+ const currentUrl = 'https://hellogithub.com/article';
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+ const $ = cheerio.load(response.data);
+ const list = $('.content .post')
+ .slice(0, 10)
+ .map((_, item) => {
+ const a = $(item).find('a.post-title').eq(0).eq(0);
+ const link = rootUrl + a.attr('href');
+ return {
+ title: a.text(),
+ link,
+ description: $(item).find('.post-description')[0].children[0].data,
+ pubDate: timezone(parseDate($(item).find('.post-meta').text(), 'YYYY-MM-DD HH:mm:ss'), +8),
+ };
+ })
+ .get();
+
+ const items = await Promise.all(
+ list.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: item.link,
+ });
+ const content = cheerio.load(detailResponse.data);
+ item.description = content('.markdown-body').html();
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: 'HelloGitHub - Article',
+ link: currentUrl,
+ item: items,
+ };
+};
diff --git a/lib/v2/hellogithub/maintainer.js b/lib/v2/hellogithub/maintainer.js
new file mode 100644
index 0000000000..e5aff75018
--- /dev/null
+++ b/lib/v2/hellogithub/maintainer.js
@@ -0,0 +1,5 @@
+module.exports = {
+ '/article': ['moke8'],
+ '/ranking/:type?': ['moke8'],
+ '/month': ['moke8'],
+};
diff --git a/lib/v2/hellogithub/month.js b/lib/v2/hellogithub/month.js
new file mode 100644
index 0000000000..84303b3de3
--- /dev/null
+++ b/lib/v2/hellogithub/month.js
@@ -0,0 +1,42 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ const rootUrl = 'https://hellogithub.com';
+ const currentUrl = 'https://hellogithub.com/article';
+ const response = await got({
+ method: 'get',
+ url: rootUrl,
+ });
+ const $ = cheerio.load(response.data);
+ let count = $('.pricing-table-price').eq(0).text();
+ count = count.replace(/[^0-9]/gi, '');
+ let start = count - 10;
+ const PromiseArr = [];
+ for (start; start <= count; start++) {
+ PromiseArr.push(
+ new Promise((resolve) => {
+ const link = `https://hellogithub.com/periodical/volume/${start}/`;
+ const issueNum = start;
+ return ctx.cache.tryGet(link, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: link,
+ });
+ const $ = cheerio.load(detailResponse.data);
+ return resolve({
+ title: '第' + issueNum + '期',
+ link,
+ description: $('.content').html(),
+ });
+ });
+ })
+ );
+ }
+ const items = await Promise.all(PromiseArr);
+ ctx.state.data = {
+ title: 'HelloGitHub - Article',
+ link: currentUrl,
+ item: items,
+ };
+};
diff --git a/lib/v2/hellogithub/radar.js b/lib/v2/hellogithub/radar.js
new file mode 100644
index 0000000000..78277b4d85
--- /dev/null
+++ b/lib/v2/hellogithub/radar.js
@@ -0,0 +1,25 @@
+module.exports = {
+ 'hellogithub.com': {
+ _name: 'HelloGitHub',
+ '.': [
+ {
+ title: '文章列表',
+ docs: 'https://docs.rsshub.app/programming.html#hellogithub',
+ source: ['/article', '/article/?url=/periodical/volume/'],
+ target: '/hellogithub/article',
+ },
+ {
+ title: '编程语言排行榜',
+ docs: 'https://docs.rsshub.app/programming.html#hellogithub',
+ source: '/report/:type/?url=/periodical/volume/',
+ target: '/hellogithub/ranking/:type',
+ },
+ {
+ title: '月刊',
+ docs: 'https://docs.rsshub.app/programming.html#hellogithub',
+ source: '/periodical/volume/',
+ target: '/hellogithub/month',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/hellogithub/ranking.js b/lib/v2/hellogithub/ranking.js
new file mode 100644
index 0000000000..0ff8b70900
--- /dev/null
+++ b/lib/v2/hellogithub/ranking.js
@@ -0,0 +1,39 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ let type;
+ switch (ctx.params.type) {
+ case 'db':
+ type = 'db-engines';
+ break;
+ case 'webserver':
+ type = 'netcraft';
+ break;
+ default:
+ type = 'tiobe';
+ break;
+ }
+ const rootUrl = 'https://hellogithub.com/report/' + type;
+ ctx.state.data = {
+ title: 'HelloGitHub - ranking',
+ link: rootUrl,
+ item: await ctx.cache.tryGet(rootUrl, async () => {
+ const response = await got({
+ method: 'get',
+ url: rootUrl,
+ });
+ const $ = cheerio.load(response.data);
+ const content = $('.content');
+ const title = $('.header').find('h1');
+
+ return [
+ {
+ title: title.text(),
+ link: rootUrl,
+ description: content.html(),
+ },
+ ];
+ }),
+ };
+};
diff --git a/lib/v2/hellogithub/router.js b/lib/v2/hellogithub/router.js
new file mode 100644
index 0000000000..6d66d79aee
--- /dev/null
+++ b/lib/v2/hellogithub/router.js
@@ -0,0 +1,5 @@
+module.exports = (router) => {
+ router.get('/article', require('./article'));
+ router.get('/month', require('./month'));
+ router.get('/ranking/:type?', require('./ranking'));
+};