diff --git a/lib/v2/m4/index.js b/lib/v2/m4/index.js
new file mode 100644
index 0000000000..ec63c69461
--- /dev/null
+++ b/lib/v2/m4/index.js
@@ -0,0 +1,82 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const timezone = require('@/utils/timezone');
+const { parseDate } = require('@/utils/parse-date');
+const { art } = require('@/utils/render');
+const path = require('path');
+
+module.exports = async (ctx) => {
+ const { id = 'news', category = 'china' } = ctx.params;
+ const limit = ctx.query.limit ? Number.parseInt(ctx.query.limit, 10) : 30;
+
+ const rootUrl = `http://${id}.m4.cn`;
+ const currentUrl = new URL(category ? `/${category.replace(/\/$/, '')}/` : '/', rootUrl).href;
+
+ const { data: response } = await got(currentUrl);
+
+ const $ = cheerio.load(response);
+
+ let items = $('div.articleitem0 div.aheader0')
+ .slice(0, limit)
+ .toArray()
+ .map((item) => {
+ item = $(item);
+
+ const a = item.find('a').first();
+
+ return {
+ title: a.text(),
+ link: a.prop('href'),
+ description: art(path.join(__dirname, 'templates/description.art'), {
+ images: [
+ {
+ src: item.parent().find('div.aimg0 a img').prop('src'),
+ alt: a.text(),
+ },
+ ],
+ }),
+ category: item
+ .find('a.aclass')
+ .toArray()
+ .map((c) => $(c).text().replaceAll('[]', '').trim()),
+ pubDate: timezone(parseDate(item.find('span.atime').text()), +8),
+ };
+ });
+
+ items = await Promise.all(
+ items.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const { data: detailResponse } = await got(item.link);
+
+ const content = cheerio.load(detailResponse);
+
+ item.title = content('h1').first().text();
+ item.description = art(path.join(__dirname, 'templates/description.art'), {
+ intro: content('div.aintro1, p.cont-summary').text(),
+ description: content('div.content0, div.cont-detail').html(),
+ });
+ item.category = content('span.dd0 a, a[rel="category"]')
+ .toArray()
+ .map((c) => content(c).text())
+ .slice(1);
+ item.pubDate = timezone(parseDate(content('span.atime1, span.post-time').text()), +8);
+
+ return item;
+ })
+ )
+ );
+
+ const image = $('a.logo0_b img').prop('src');
+
+ ctx.state.data = {
+ item: items,
+ title: $('title').text(),
+ link: currentUrl,
+ description: $('meta[name="description"]').prop('content'),
+ language: 'zh',
+ image,
+ subtitle: $('meta[name="keywords"]').prop('content'),
+ author: $('meta[name="author"]').prop('content'),
+ allowEmpty: true,
+ };
+};
diff --git a/lib/v2/m4/maintainer.js b/lib/v2/m4/maintainer.js
new file mode 100644
index 0000000000..cc56280518
--- /dev/null
+++ b/lib/v2/m4/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/mil/:category?': ['nczitzk'],
+ '/news/:category?': ['nczitzk'],
+};
diff --git a/lib/v2/m4/radar.js b/lib/v2/m4/radar.js
new file mode 100644
index 0000000000..097604a24d
--- /dev/null
+++ b/lib/v2/m4/radar.js
@@ -0,0 +1,87 @@
+module.exports = {
+ 'm4.cn': {
+ _name: '四月网',
+ news: [
+ {
+ title: '要闻 - 国内新闻',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
+ source: ['/china/'],
+ target: '/m4/news/china',
+ },
+ {
+ title: '要闻 - 国际新闻',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
+ source: ['/world/'],
+ target: '/m4/news/world',
+ },
+ {
+ title: '要闻 - 民生',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
+ source: ['/livelihood/'],
+ target: '/m4/news/livelihood',
+ },
+ {
+ title: '要闻 - 社会',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
+ source: ['/society/'],
+ target: '/m4/news/society',
+ },
+ {
+ title: '要闻 - 财经',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
+ source: ['/finance/'],
+ target: '/m4/news/finance',
+ },
+ {
+ title: '要闻 - 科技',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-yao-wen',
+ source: ['/tech/'],
+ target: '/m4/news/tech',
+ },
+ ],
+ mil: [
+ {
+ title: '军事 - 中国军情',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
+ source: ['/china/'],
+ target: '/m4/mil/china',
+ },
+ {
+ title: '军事 - 国际军情',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
+ source: ['/world/'],
+ target: '/m4/mil/world',
+ },
+ {
+ title: '军事 - 军事评论',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
+ source: ['/views/'],
+ target: '/m4/mil/views',
+ },
+ {
+ title: '军事 - 军事历史',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
+ source: ['/history/'],
+ target: '/m4/mil/history',
+ },
+ {
+ title: '军事 - 军迷说',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
+ source: ['/talk/'],
+ target: '/m4/mil/talk',
+ },
+ {
+ title: '军事 - 图说军事',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
+ source: ['/photo/'],
+ target: '/m4/mil/photo',
+ },
+ {
+ title: '军事 - 武器库',
+ docs: 'https://docs.rsshub.app/routes/new-media#si-yue-wang-jun-shi',
+ source: ['/arms/'],
+ target: '/m4/mil/arms',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/m4/router.js b/lib/v2/m4/router.js
new file mode 100644
index 0000000000..6e412f06b1
--- /dev/null
+++ b/lib/v2/m4/router.js
@@ -0,0 +1,3 @@
+module.exports = (router) => {
+ router.get('/:id?/:category*', require('./'));
+};
diff --git a/lib/v2/m4/templates/description.art b/lib/v2/m4/templates/description.art
new file mode 100644
index 0000000000..249654e7e6
--- /dev/null
+++ b/lib/v2/m4/templates/description.art
@@ -0,0 +1,21 @@
+{{ if images }}
+ {{ each images image }}
+ {{ if image?.src }}
+
+
{{ intro }}+{{ /if }} + +{{ if description }} + {{@ description }} +{{ /if }} \ No newline at end of file diff --git a/website/docs/routes/new-media.mdx b/website/docs/routes/new-media.mdx index d95d8d02ab..121f127432 100644 --- a/website/docs/routes/new-media.mdx +++ b/website/docs/routes/new-media.mdx @@ -4328,6 +4328,34 @@