diff --git a/docs/README.md b/docs/README.md
index 6f6f0ac88..eb4f4e136 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -246,6 +246,22 @@ areaID: 分区 ID 分区增删较多,可通过 [分区列表](https://api.live
order: 排序方式,live_time 开播时间,online 人气
+## bangumi
+
+### 放送列表
+
+举例: [https://rsshub.app/bangumi/calendar/today](https://rsshub.app/bangumi/calendar/today)
+
+路由: `/bangumi/calendar/today`
+
+参数: 无
+
+::: tip 提示
+
+可以配合[内容过滤](#内容过滤)使用
+
+:::
+
## 微博
### 博主
diff --git a/router.js b/router.js
index f9d803575..905a79832 100644
--- a/router.js
+++ b/router.js
@@ -89,6 +89,9 @@ router.get('/bilibili/live/room/:roomID', require('./routes/bilibili/liveRoom'))
router.get('/bilibili/live/search/:key/:order', require('./routes/bilibili/liveSearch'));
router.get('/bilibili/live/area/:areaID/:order', require('./routes/bilibili/liveArea'));
+// bangumi
+router.get('/bangumi/calendar/today', require('./routes/bangumi/calendar/today'));
+
// 微博
router.get('/weibo/user/:uid', require('./routes/weibo/user'));
router.get('/weibo/user2/:uid', require('./routes/weibo/user2'));
diff --git a/routes/bangumi/calendar/_base.js b/routes/bangumi/calendar/_base.js
new file mode 100644
index 000000000..297e6908a
--- /dev/null
+++ b/routes/bangumi/calendar/_base.js
@@ -0,0 +1,47 @@
+const axios = require('../../../utils/axios');
+const config = require('../../../config');
+
+module.exports = async (ctx) => {
+ const bgmCalendarUrl = 'https://api.bgm.tv/calendar';
+ const bgmDataUrl = 'https://cdn.jsdelivr.net/npm/bangumi-data/dist/data.json';
+
+ const url = [bgmCalendarUrl, bgmDataUrl];
+
+ const cache = await Promise.all(url.map(ctx.cache.get));
+ const result = await Promise.all(
+ cache.map(async (c, i) => {
+ if (c !== undefined) {
+ return Promise.resolve(JSON.parse(c));
+ } else {
+ const response = await axios({
+ method: 'get',
+ url: url[i],
+ headers: {
+ 'User-Agent': config.ua,
+ },
+ });
+ const data = response.data;
+
+ if (i === 1) {
+ // 只保留有 bangumi id 的番剧
+ const length = data.items.length;
+ const items = [];
+ for (let index = 0; index < length; index++) {
+ const item = data.items[index];
+ const bgm_site = item.sites.find((s) => s.site === 'bangumi');
+ if (bgm_site) {
+ item.bgm_id = bgm_site.id;
+ items.push(item);
+ }
+ }
+ data.items = items;
+ }
+
+ ctx.cache.set(url[i], JSON.stringify(data), 86400);
+ return Promise.resolve(data);
+ }
+ })
+ );
+
+ return result;
+};
diff --git a/routes/bangumi/calendar/today.js b/routes/bangumi/calendar/today.js
new file mode 100644
index 000000000..88c07c58f
--- /dev/null
+++ b/routes/bangumi/calendar/today.js
@@ -0,0 +1,68 @@
+const getData = require('./_base');
+
+module.exports = async (ctx) => {
+ const [list, data] = await getData(ctx);
+ const siteMeta = data.siteMeta;
+
+ const now = new Date(Date.now());
+
+ now.setHours(now.getHours() + 9);
+ const day = now.getUTCDay();
+
+ const todayList = list.filter((l) => l.weekday.id % 7 === day)[0];
+
+ const todayBgmId = todayList.items.map((t) => `${t.id}`);
+ const images = todayList.items.reduce((p, c) => {
+ p[c.id] = (c.images || {}).large;
+ return p;
+ }, {});
+
+ const todayBgm = data.items.filter((d) => todayBgmId.includes(d.bgm_id));
+ todayBgm.forEach((bgm) => {
+ bgm.image = images[bgm.bgm_id];
+ });
+
+ ctx.state.data = {
+ title: 'bangumi 每日放送',
+ link: 'https://bgm.tv/calendar',
+ item: todayBgm.map((bgm) => {
+ const updated = new Date(Date.now());
+ updated.setSeconds(0);
+ const begin = new Date(bgm.begin || updated);
+ updated.setHours(begin.getHours());
+ updated.setMinutes(begin.getMinutes());
+ updated.setSeconds(begin.getSeconds());
+
+ const image = ``;
+ const content =
+ image +
+ '