diff --git a/docs/new-media.md b/docs/new-media.md
index e13843510f..8536725a82 100644
--- a/docs/new-media.md
+++ b/docs/new-media.md
@@ -2031,6 +2031,14 @@ others = 热点新闻 + 滚动新闻
+### 标签
+
+
+
+分类名同上。
+
+
+
## 加美财经
diff --git a/lib/router.js b/lib/router.js
index 7f1b646e8f..d0c072bd9e 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -338,9 +338,6 @@ router.get('/t66y/:id/:type?', lazyloadRouteHandler('./routes/t66y/index'));
// 色中色
router.get('/sexinsex/:id/:type?', lazyloadRouteHandler('./routes/sexinsex/index'));
-// 机核
-router.get('/gcores/category/:category', lazyloadRouteHandler('./routes/gcores/category'));
-
// 国家地理
router.get('/natgeo/dailyphoto', lazyloadRouteHandler('./routes/natgeo/dailyphoto'));
router.get('/natgeo/:cat/:type?', lazyloadRouteHandler('./routes/natgeo/natgeo'));
diff --git a/lib/routes/gcores/category.js b/lib/routes/gcores/category.js
deleted file mode 100644
index 6123db5da1..0000000000
--- a/lib/routes/gcores/category.js
+++ /dev/null
@@ -1,127 +0,0 @@
-const got = require('@/utils/got');
-const cheerio = require('cheerio');
-
-module.exports = async (ctx) => {
- const category = ctx.params.category;
- const url = `https://www.gcores.com/${category}`;
- const res = await got({
- method: 'get',
- url,
- });
- const data = res.data;
- const $ = cheerio.load(data);
- const feedTitle = $('title').text();
-
- const list = $('.original.am_card.original-normal')
- .map(function () {
- const item = {
- url: $(this).find('a.am_card_content.original_content').attr('href'),
- title: $(this).find('h3.am_card_title').text(),
- };
- return item;
- })
- .get();
-
- const out = await Promise.all(
- list.map(async (item) => {
- const articleUrl = `https://www.gcores.com${item.url}`;
-
- const cache = await ctx.cache.get(articleUrl);
- if (cache) {
- return Promise.resolve(JSON.parse(cache));
- }
- const itemRes = await got({
- method: 'get',
- url: articleUrl,
- });
-
- const itemPage = itemRes.data;
- const $ = cheerio.load(itemPage);
-
- let articleData = await got(`https://www.gcores.com/gapi/v1${item.url}?include=media`);
- articleData = articleData.data.data;
- let cover;
- if (articleData.attributes.cover) {
- cover = `
`;
- } else if (articleData.attributes.thumb) {
- cover = `
`;
- } else {
- cover = '';
- }
-
- // replace figure with img
- const articleContent = JSON.parse(articleData.attributes.content);
- const entityRangeMap = {};
- for (const block of articleContent.blocks || []) {
- if (block.entityRanges.length) {
- entityRangeMap[block.key] = block.entityRanges;
- }
- }
-
- $('figure').each((i, elem) => {
- const keyAttr = elem.attribs['data-offset-key'];
- const keyMatch = /^(\w+)-(\d+)-(\d)$/.exec(keyAttr);
- let actualContent = '';
- if (keyMatch) {
- const [, key, index] = keyMatch;
- if (entityRangeMap[key] && entityRangeMap[key][index]) {
- const entityKey = entityRangeMap[key] && entityRangeMap[key][index].key;
- const entity = articleContent.entityMap[entityKey];
- actualContent = convertEntityToContent(entity);
- }
- }
-
- if (actualContent) {
- $(elem).replaceWith(actualContent);
- }
- });
-
- // remove editor toolbar img
- $('.md-editor-toolbar').replaceWith('');
- // remove hidden tip block
- $('.story_hidden').replaceWith('');
-
- const content = $('.story.story-show').html();
- const single = {
- title: item.title,
- description: cover + content,
- link: articleUrl,
- guid: articleUrl,
- };
- ctx.cache.set(articleUrl, JSON.stringify(single));
- return Promise.resolve(single);
- })
- );
- ctx.state.data = {
- title: feedTitle,
- link: url,
- item: out,
- };
-};
-
-function convertEntityToContent(entity) {
- const { type, data } = entity;
- switch (type) {
- case 'IMAGE':
- return `
-
-
-${data.caption ? `${data.caption}` : ''}
-`;
-
- case 'GALLERY':
- return data.images
- .map(
- (image, i, arr) => `
-
-
-${data.caption || ''} (${i + 1}/${arr.length}) ${image.caption || ''}
-
- `
- )
- .join('');
-
- default:
- return '';
- }
-}
diff --git a/lib/v2/gcores/category.js b/lib/v2/gcores/category.js
new file mode 100644
index 0000000000..a289b33f0c
--- /dev/null
+++ b/lib/v2/gcores/category.js
@@ -0,0 +1,126 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category;
+ const url = `https://www.gcores.com/${category}`;
+ const res = await got({
+ method: 'get',
+ url,
+ });
+ const data = res.data;
+ const $ = cheerio.load(data);
+ const feedTitle = $('title').text();
+
+ const list = $('.original.am_card.original-normal')
+ .map(function () {
+ const item = {
+ url: $(this).find('a.am_card_content.original_content').attr('href'),
+ title: $(this).find('h3.am_card_title').text(),
+ category: $(this).find('span.original_category>a').text(),
+ };
+ return item;
+ })
+ .get();
+
+ const out = await Promise.all(
+ list.map((item) => {
+ const articleUrl = `https://www.gcores.com${item.url}`;
+
+ return ctx.cache.tryGet(articleUrl, async () => {
+ const itemRes = await got({
+ method: 'get',
+ url: articleUrl,
+ });
+
+ const itemPage = itemRes.data;
+ const $ = cheerio.load(itemPage);
+
+ let articleData = await got(`https://www.gcores.com/gapi/v1${item.url}?include=media`);
+
+ articleData = articleData.data.data;
+ let cover;
+ if (articleData.attributes.cover) {
+ cover = `
`;
+ } else if (articleData.attributes.thumb) {
+ cover = `
`;
+ } else {
+ cover = '';
+ }
+
+ // replace figure with img
+ const articleContent = JSON.parse(articleData.attributes.content);
+ const entityRangeMap = {};
+ for (const block of articleContent.blocks || []) {
+ if (block.entityRanges.length) {
+ entityRangeMap[block.key] = block.entityRanges;
+ }
+ }
+
+ $('figure').each((i, elem) => {
+ const keyAttr = elem.attribs['data-offset-key'];
+ const keyMatch = /^(\w+)-(\d+)-(\d)$/.exec(keyAttr);
+ let actualContent = '';
+ if (keyMatch) {
+ const [, key, index] = keyMatch;
+ if (entityRangeMap[key] && entityRangeMap[key][index]) {
+ const entityKey = entityRangeMap[key] && entityRangeMap[key][index].key;
+ const entity = articleContent.entityMap[entityKey];
+ actualContent = convertEntityToContent(entity);
+ }
+ }
+
+ if (actualContent) {
+ $(elem).replaceWith(actualContent);
+ }
+ });
+
+ // remove editor toolbar img
+ $('.md-editor-toolbar').replaceWith('');
+ // remove hidden tip block
+ $('.story_hidden').replaceWith('');
+
+ const content = $('.story.story-show').html();
+ return {
+ title: item.title,
+ description: cover + content,
+ category: item.category,
+ link: articleUrl,
+ guid: articleUrl,
+ };
+ });
+ })
+ );
+ ctx.state.data = {
+ title: feedTitle,
+ link: url,
+ item: out,
+ };
+};
+
+function convertEntityToContent(entity) {
+ const { type, data } = entity;
+ switch (type) {
+ case 'IMAGE':
+ return `
+
+
+${data.caption ? `${data.caption}` : ''}
+`;
+
+ case 'GALLERY':
+ return data.images
+ .map(
+ (image, i, arr) => `
+
+
+${data.caption || ''} (${i + 1}/${arr.length}) ${image.caption || ''}
+
+ `
+ )
+ .join('');
+
+ default:
+ return '';
+ }
+}
diff --git a/lib/v2/gcores/maintainer.js b/lib/v2/gcores/maintainer.js
new file mode 100644
index 0000000000..f1842790b2
--- /dev/null
+++ b/lib/v2/gcores/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/category/:category': ['MoguCloud', 'StevenRCE0'],
+ '/tag/:tag/:category?': ['StevenRCE0'],
+};
diff --git a/lib/v2/gcores/radar.js b/lib/v2/gcores/radar.js
new file mode 100644
index 0000000000..40bfcdb529
--- /dev/null
+++ b/lib/v2/gcores/radar.js
@@ -0,0 +1,19 @@
+module.exports = {
+ 'gcores.com': {
+ _name: '机核网',
+ '.': [
+ {
+ title: '分类',
+ docs: 'https://docs.rsshub.app/new-media.html#ji-he-wang-fen-lei',
+ source: ['/:category'],
+ target: '/gcores/category/:category',
+ },
+ {
+ title: '标签',
+ docs: 'https://docs.rsshub.app/new-media.html#ji-he-wang-biao-qian',
+ source: ['/categories/:tag', '/'],
+ target: '/gcores/tag/:tag',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/gcores/router.js b/lib/v2/gcores/router.js
new file mode 100644
index 0000000000..4cf4aa2751
--- /dev/null
+++ b/lib/v2/gcores/router.js
@@ -0,0 +1,4 @@
+module.exports = function (router) {
+ router.get('/category/:category', require('./category'));
+ router.get('/tag/:tag/:category?', require('./tag'));
+};
diff --git a/lib/v2/gcores/tag.js b/lib/v2/gcores/tag.js
new file mode 100644
index 0000000000..8722ce1623
--- /dev/null
+++ b/lib/v2/gcores/tag.js
@@ -0,0 +1,126 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ const tag = ctx.params.tag;
+ const category = ctx.params.category;
+ const url = `https://www.gcores.com/categories/${tag + (category ? `?tab=${category}` : '')}`;
+ const res = await got({
+ method: 'get',
+ url,
+ });
+ const data = res.data;
+ const $ = cheerio.load(data);
+ const feedTitle = $('title').text();
+
+ const list = $('.original.am_card.original-normal')
+ .map(function () {
+ const item = {
+ url: $(this).find('a.am_card_content.original_content').attr('href'),
+ title: $(this).find('h3.am_card_title').text(),
+ category: $(this).find('span.original_category>a').text(),
+ };
+ return item;
+ })
+ .get();
+
+ const out = await Promise.all(
+ list.map((item) => {
+ const articleUrl = `https://www.gcores.com${item.url}`;
+
+ return ctx.cache.tryGet(articleUrl, async () => {
+ const itemRes = await got({
+ method: 'get',
+ url: articleUrl,
+ });
+
+ const itemPage = itemRes.data;
+ const $ = cheerio.load(itemPage);
+
+ let articleData = await got(`https://www.gcores.com/gapi/v1${item.url}?include=media`);
+
+ articleData = articleData.data.data;
+ let cover;
+ if (articleData.attributes.cover) {
+ cover = `
`;
+ } else if (articleData.attributes.thumb) {
+ cover = `
`;
+ } else {
+ cover = '';
+ }
+
+ // replace figure with img
+ const articleContent = JSON.parse(articleData.attributes.content);
+ const entityRangeMap = {};
+ for (const block of articleContent.blocks || []) {
+ if (block.entityRanges.length) {
+ entityRangeMap[block.key] = block.entityRanges;
+ }
+ }
+
+ $('figure').each((i, elem) => {
+ const keyAttr = elem.attribs['data-offset-key'];
+ const keyMatch = /^(\w+)-(\d+)-(\d)$/.exec(keyAttr);
+ let actualContent = '';
+ if (keyMatch) {
+ const [, key, index] = keyMatch;
+ if (entityRangeMap[key] && entityRangeMap[key][index]) {
+ const entityKey = entityRangeMap[key] && entityRangeMap[key][index].key;
+ const entity = articleContent.entityMap[entityKey];
+ actualContent = convertEntityToContent(entity);
+ }
+ }
+
+ if (actualContent) {
+ $(elem).replaceWith(actualContent);
+ }
+ });
+
+ // remove editor toolbar img
+ $('.md-editor-toolbar').replaceWith('');
+ // remove hidden tip block
+ $('.story_hidden').replaceWith('');
+
+ const content = $('.story.story-show').html();
+ return {
+ title: item.title,
+ description: cover + content,
+ link: articleUrl,
+ guid: articleUrl,
+ };
+ });
+ })
+ );
+ ctx.state.data = {
+ title: feedTitle,
+ link: url,
+ item: out,
+ };
+};
+
+function convertEntityToContent(entity) {
+ const { type, data } = entity;
+ switch (type) {
+ case 'IMAGE':
+ return `
+
+
+${data.caption ? `${data.caption}` : ''}
+`;
+
+ case 'GALLERY':
+ return data.images
+ .map(
+ (image, i, arr) => `
+
+
+${data.caption || ''} (${i + 1}/${arr.length}) ${image.caption || ''}
+
+ `
+ )
+ .join('');
+
+ default:
+ return '';
+ }
+}