diff --git a/README.md b/README.md
index b35d37469e..a08e6055a1 100644
--- a/README.md
+++ b/README.md
@@ -114,7 +114,9 @@ RSSHub 是一个轻量、易于扩展的 RSS 生成器,可以给任何奇奇
* 熊猫直播
* 直播间开播下播
* V2EX
- * 最热主题/最新主题
+ * 最热/最新主题
+* Telegram
+ * 频道
## 鸣谢
diff --git a/config.js b/config.js
index 70c2e11351..3ced7741d7 100644
--- a/config.js
+++ b/config.js
@@ -30,4 +30,7 @@ module.exports = {
youtube: {
key: process.env.YOUTUBE_KEY,
},
+ telegram: {
+ token: process.env.TELEGRAM_TOKEN,
+ },
};
diff --git a/docs/README.md b/docs/README.md
index d0d267268d..fa1b9fb325 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -883,10 +883,26 @@ key: 产品密钥
## V2EX
-### 最热主题/最新主题
+### 最热/最新主题
举例: [https://rsshub.app/v2ex/topics/latest](https://rsshub.app/v2ex/topics/latest)
路由: `/v2ex/topics/:type`
-参数: type,hot 或 latest 二者之一
+参数: type: hot 或 latest
+
+## Telegram
+
+### 频道
+
+::: tip 提示
+
+订阅要求:将机器人 [@RSSHub_bot](https://t.me/RSSHub_bot) 加为频道管理员,然后发一条消息后才可正常获取数据
+
+:::
+
+举例: [https://rsshub.app/telegram/channel/awesomeDIYgod](https://rsshub.app/telegram/channel/awesomeDIYgod)
+
+路由: `/telegram/channel/:username`
+
+参数: username,频道 username
diff --git a/docs/install/README.md b/docs/install/README.md
index aadac25fde..5e050569ff 100644
--- a/docs/install/README.md
+++ b/docs/install/README.md
@@ -364,3 +364,7 @@ gcloud app deploy
* `youtube`: [申请地址](https://console.developers.google.com/)
* `YOUTUBE_KEY`: YouTube API Key
+
+* `telegram`: [Telegram 机器人](https://telegram.org/blog/bot-revolution)
+
+ * `TELEGRAM_TOKEN`: Telegram 机器人 token
diff --git a/router.js b/router.js
index 027e109c14..affd64d4f1 100644
--- a/router.js
+++ b/router.js
@@ -226,4 +226,11 @@ router.get('/panda/room/:id', require('./routes/panda/room'));
// v2ex
router.get('/v2ex/topics/:type', require('./routes/v2ex/topics'));
+// Telegram
+if (config.telegram && config.telegram.token) {
+ router.get('/telegram/channel/:username', require('./routes/telegram/channel'));
+} else {
+ logger.warn('Telegram RSS is disabled for lacking config.');
+}
+
module.exports = router;
diff --git a/routes/telegram/channel.js b/routes/telegram/channel.js
new file mode 100644
index 0000000000..af5b61d0a3
--- /dev/null
+++ b/routes/telegram/channel.js
@@ -0,0 +1,80 @@
+const axios = require('../../utils/axios');
+const config = require('../../config');
+const logger = require('../../utils/logger');
+
+let botName = '';
+axios({
+ method: 'get',
+ url: `https://api.telegram.org/bot${config.telegram.token}/getMe`,
+})
+ .then(function(response) {
+ botName = response.data.result.username;
+ })
+ .catch(function(error) {
+ logger.error('Error in getting Telegram bot name: ' + error);
+ });
+
+module.exports = async (ctx) => {
+ const username = ctx.params.username;
+
+ const response = await axios({
+ method: 'get',
+ url: `https://api.telegram.org/bot${config.telegram.token}/getUpdates?allowed_updates=[%22channel_post%22]`,
+ });
+
+ const data = response.data.result.filter((item) => item.channel_post && item.channel_post.chat && item.channel_post.chat.username === username).reverse();
+
+ ctx.state.data = {
+ title: data[0] ? `${data[0].channel_post.chat.title} - Telegram 频道` : `未获取到信息: 请将 Telegram 机器人 @${botName} 设为频道管理员后发一条或以上有效消息完成配置`,
+ link: `https://t.me/${username}`,
+ item: data.map((item) => {
+ item = item.channel_post;
+ let text = item.text || item.caption || '';
+ const media = ['photo', 'audio', 'document', 'game', 'sticker', 'video', 'voice', 'contact', 'location', 'venue'];
+ media.forEach((me) => {
+ if (item[me]) {
+ text += ` [${me}]`;
+ }
+ });
+
+ let html = text;
+
+ if (item.entities) {
+ const enter = [];
+ item.entities.forEach((entity) => {
+ switch (entity.type) {
+ case 'text_link':
+ enter.push([entity.offset, ``], [entity.offset + entity.length, '']);
+ break;
+ case 'bold':
+ enter.push([entity.offset, ''], [entity.offset + entity.length, '']);
+ break;
+ case 'hashtag':
+ case 'italic':
+ enter.push([entity.offset, ''], [entity.offset + entity.length, '']);
+ break;
+ }
+ });
+ enter.sort((a, b) => a[0] - b[0]);
+ if (enter.length) {
+ text.slice(0, enter[0][0]) + enter[0][1] + text.slice(enter[0][0], enter[1][0]) + enter[1][1] + text.slice(enter[1][0], enter[2][0]) + enter[2][1] + text.slice(enter[2][0]);
+ html = text.slice(0, enter[0][0]);
+ enter.forEach((en, index) => {
+ if (index !== enter.length - 1) {
+ html += enter[index][1] + text.slice(enter[index][0], enter[index + 1][0]);
+ } else {
+ html += enter[index][1] + text.slice(enter[index][0]);
+ }
+ });
+ }
+ }
+
+ return {
+ title: text.length > 24 ? text.slice(0, 24) + '...' : text,
+ description: html,
+ pubDate: new Date(item.date * 1000).toUTCString(),
+ link: `https://t.me/${username}/${item.message_id}`,
+ };
+ }),
+ };
+};