diff --git a/docs/en/new-media.md b/docs/en/new-media.md
index 0762f1bdab..1d31bd28ce 100644
--- a/docs/en/new-media.md
+++ b/docs/en/new-media.md
@@ -577,3 +577,15 @@ Language
### Newsroom
+
+### Speeches
+
+
+
+Language
+
+| English | العربية | 中文 | Français | Русский | Español | Português |
+| ------- | ------- | ---- | -------- | ------- | ------- | --------- |
+| en | ar | zh | fr | ru | es | pt |
+
+
\ No newline at end of file
diff --git a/docs/new-media.md b/docs/new-media.md
index 790ee20c40..1d40083a28 100644
--- a/docs/new-media.md
+++ b/docs/new-media.md
@@ -2310,6 +2310,18 @@ column 为 third 时可选的 category:
+### 总干事的讲话
+
+
+
+语言
+
+| English | العربية | 中文 | Français | Русский | Español | Português |
+| ------- | ------- | ---- | -------- | ------- | ------- | --------- |
+| en | ar | zh | fr | ru | es | pt |
+
+
+
## 数英网
### 数英网最新文章
diff --git a/lib/router.js b/lib/router.js
index e3ab894528..9de5aadae0 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1692,6 +1692,7 @@ router.get('/nintendo/system-update', lazyloadRouteHandler('./routes/nintendo/sy
// 世界卫生组织
router.get('/who/news-room/:type', lazyloadRouteHandler('./routes/who/news-room'));
+router.get('/who/speeches/:language?', require('./routes/who/speeches'));
router.get('/who/news/:language?', require('./routes/who/news'));
// 福利资源-met.red
diff --git a/lib/routes/who/speeches.js b/lib/routes/who/speeches.js
new file mode 100644
index 0000000000..268ea98926
--- /dev/null
+++ b/lib/routes/who/speeches.js
@@ -0,0 +1,45 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx) => {
+ const language = ctx.params.language || 'en';
+
+ const rootUrl = 'https://www.who.int';
+ const currentUrl = `${rootUrl}/${language === 'en' ? '' : `${language}/`}director-general/speeches`;
+ const apiUrl = `${rootUrl}/api/hubs/speeches?sf_culture=${language}&$orderby=PublicationDateAndTime%20desc&$select=Title,PublicationDateAndTime,ItemDefaultUrl`;
+
+ const response = await got({
+ method: 'get',
+ url: apiUrl,
+ });
+
+ const list = response.data.value.map((item) => ({
+ title: item.Title,
+ link: `${currentUrl}/detail/${item.ItemDefaultUrl}`,
+ pubDate: parseDate(item.PublicationDateAndTime),
+ }));
+
+ 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('.sf-detail-body-wrapper').html();
+
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: 'Speeches - WHO',
+ link: currentUrl,
+ item: items,
+ };
+};