diff --git a/docs/traditional-media.md b/docs/traditional-media.md index 20d3449d6..f805d38fc 100644 --- a/docs/traditional-media.md +++ b/docs/traditional-media.md @@ -1124,15 +1124,44 @@ IT・科学 tech_science -### 新花城(广州市融媒体中心) +## 广州市融媒体中心 - +### 频道 -::: tip 提示 + -`频道名(channel)` 可在对应频道 url 后的参数中获取,如 `首页` 的栏目 url 为`https://huacheng.gz-cmc.com/channel/shouye/index.html`, `频道名` 即为 `shouye`。 +已知支持的站点及对应的`站点代码`如下: -::: +| 站点 / 客户端名 | 营运机构 | 代码 | +| :--------------------------------------------------------: | :--------------: | :--------------------------------------------: | +| [新花城](https://www.gz-cmc.com "新花城") | 广州日报社 | `huacheng` | +| [广州白云](https://guangzhoubaiyun.gz-cmc.com/ "广州白云") | 白云区融媒体中心 | `guangzhoubaiyun` | +| 到黄埔去 | 黄埔区融媒体中心 | `daohuangpuqu` | +| 掌上番禺 | 番禺区融媒体中心 | `zhangshangfanyu`
(注:此处非笔误 = =) | +| 阅增城 | 增城区融媒体中心 | `yuezengcheng` | + +如有上表未列出的站点,欢迎补充。 + +`频道代码`获取方式: + +1. 在对应频道 url 后的参数中获取,如`首页`的栏目 url 为`https://huacheng.gz-cmc.com/channel/shouye/index.html`, `频道代码`即为`shouye`。 +2. 进入相应站点的客户端后抓包。 + +黄埔、增城、番禺三区的站点无网页,需采用抓包的方式获取频道代码。现列出部分: + +| 频道名 | 代码 | +| :------------------------: | :------: | +| 黄埔 - 首页 | `sy` | +| 黄埔 -《湾区时报》最新一期 | `hpxsd` | +| 黄埔 - 民生 | `ms` | +| 黄埔 - 企明星 | `qmx` | +| 增城 - 首页 | `shouye` | +| 增城 - 身边 | `sb` | +| 增城 - 本地 | `zcfb` | +| 番禺 - 首页 | `shouye` | +| 番禺 - 身边 | `yw` | +| 番禺 - 生活 | `sh` | +| 番禺 - 教育 | `jy` |
diff --git a/lib/v2/gz-cmc/index.js b/lib/v2/gz-cmc/index.js new file mode 100644 index 000000000..161b2bf3c --- /dev/null +++ b/lib/v2/gz-cmc/index.js @@ -0,0 +1,137 @@ +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) => { + let channel = ''; + let site = ''; + let siteName = '广州市融媒体中心'; + let siteLink = 'https://www.gz-cmc.com/'; + switch (ctx.params.site) { + case 'huacheng': + case 'xinhuacheng': + case 'hc': + case 'guangzhou': + case 'gz': + case '': + channel = ctx.params.channel ?? 'shouye'; + site = 'huacheng'; + siteName = '广州日报——新花城'; + siteLink = `https://huacheng.gz-cmc.com/channel/${channel}/index.html`; + break; + + case 'daohuangpuqu': + case 'huangpu': + case 'hp': + channel = ctx.params.channel ?? 'sy'; + if (channel === 'wanqushibao' || channel === 'wqsb') { + channel = 'hpxsd'; + } + site = 'daohuangpuqu'; + siteName = '黄埔融媒——到黄埔去'; + siteLink = 'https://www.gz-cmc.com/html/download.html?siteId=cd4f63bdfdfd41749c7e304bc0d7a6df'; // no website available for this site + break; + + case 'zhangshangfanyu': + case 'zhangshangpanyu': + case 'panyu': + case 'py': + channel = ctx.params.channel ?? 'shouye'; + site = 'zhangshangfanyu'; // not a typo here... + siteName = '番禺融媒——掌上番禺'; + siteLink = 'https://www.gz-cmc.com/html/download.html?siteId=d755df8bb9fb49ee96052f7dee58d21b'; // no website available for this site + break; + + case 'yuezengcheng': + case 'zengcheng': + case 'zc': + channel = ctx.params.channel ?? 'shouye'; + site = 'yuezengcheng'; + siteName = '增城融媒——阅增城'; + siteLink = 'https://www.gz-cmc.com/html/download.html?siteId=78fa6d06b0dd4f27abf341e5efde035a'; // no website available for this site + break; + + case 'guangzhoubaiyun': + case 'baiyun': + case 'by': + channel = ctx.params.channel ?? 'sy'; + site = 'guangzhoubaiyun'; + siteName = '白云融媒——广州白云'; + siteLink = `https://guangzhoubaiyun.gz-cmc.com/channel/${channel}/index.html`; + break; + + default: + channel = ctx.params.channel; + site = ctx.params.site; + break; + } + const apiUrl = `https://${site}.gz-cmc.com/json/channel/${channel}/list.json`; + + const response = await got({ + method: 'get', + url: apiUrl, + }); + + let result = []; + if (site === 'daohuangpuqu' && channel === 'hpxsd') { + const { data: newResponse } = await got(response.data.list[0].data.detailJsonPath); + result = newResponse.dataList; + if (newResponse.nextJsonUrl) { + const { data: nextResponse } = await got(newResponse.nextJsonUrl); + result = [...result, ...nextResponse.dataList]; + } + } else { + result = response.data.list; + } + + const list = result + .filter((i) => i.data.contentType === 1 && i.data.linkType === 0) + .map((item) => ({ + title: item.data.title, + description: art(path.join(__dirname, 'templates/description.art'), { + thumb: item.data.mCoverImg, + }), + pubDate: timezone(parseDate(item.data.lastpublishTime), +8), + link: item.data.url, + author: item.data.author, + })); + + 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); + content('.broadcast-container').remove(); + + if (content('meta[name="description"]').attr('content')) { + item.description += '
' + content('meta[name="description"]').attr('content') + '
'; + } + item.description += content('.article-source').html() ?? ''; + + if (site === 'daohuangpuqu') { + const articleContent = content('script') + .text() + .match(/contentTxt ="(.*)";/); + item.description += articleContent ? articleContent[1].replace(/\\/g, '') : ''; + } else { + item.description += content('#articleContent').html(); + } + + return item; + }) + ) + ); + + ctx.state.data = { + title: siteName, + link: siteLink, + item: items, + }; +}; diff --git a/lib/v2/gz-cmc/maintainer.js b/lib/v2/gz-cmc/maintainer.js new file mode 100644 index 000000000..f7a851f99 --- /dev/null +++ b/lib/v2/gz-cmc/maintainer.js @@ -0,0 +1,3 @@ +module.exports = { + '/:site/:channel?': ['TimWu007'], +}; diff --git a/lib/v2/gz-cmc/radar.js b/lib/v2/gz-cmc/radar.js new file mode 100644 index 000000000..84f87c512 --- /dev/null +++ b/lib/v2/gz-cmc/radar.js @@ -0,0 +1,12 @@ +module.exports = { + 'gz-cmc.com': { + _name: '广州市融媒体中心', + '.': [ + { + title: '频道', + docs: 'https://docs.rsshub.app/traditional-media.html#guang-zhou-shi-rong-mei-ti-zhong-xin', + source: ['/'], + }, + ], + }, +}; diff --git a/lib/v2/gz-cmc/router.js b/lib/v2/gz-cmc/router.js new file mode 100644 index 000000000..e7e5ab375 --- /dev/null +++ b/lib/v2/gz-cmc/router.js @@ -0,0 +1,3 @@ +module.exports = (router) => { + router.get('/:site/:channel?', require('./index')); +}; diff --git a/lib/v2/gz-cmc/templates/description.art b/lib/v2/gz-cmc/templates/description.art new file mode 100644 index 000000000..2113e7063 --- /dev/null +++ b/lib/v2/gz-cmc/templates/description.art @@ -0,0 +1,3 @@ +{{ if thumb }} +
+{{ /if }} \ No newline at end of file diff --git a/lib/v2/gzdaily/cmc.js b/lib/v2/gzdaily/cmc.js deleted file mode 100644 index 98f2880be..000000000 --- a/lib/v2/gzdaily/cmc.js +++ /dev/null @@ -1,60 +0,0 @@ -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 channel = ctx.params.channel ?? 'shouye'; - const currentUrl = `https://huacheng.gz-cmc.com/channel/${channel}/index.html`; - - const response = await got({ - method: 'get', - url: currentUrl, - }); - - const $ = cheerio.load(response.data); - const title = $('a.brand').text().trim(); - let items = $('.news-list-row2') - .toArray() - .filter((item) => $(item).attr('contenttype') === '1' && $(item).attr('mlistpattern') === '1') - .map((item) => { - item = $(item); - return { - title: item.text().replace(/\s*/g, ''), - link: item.children('a').attr('href'), - description: art(path.join(__dirname, 'templates/description.art'), { - thumb: item.find('img').attr('src'), - }), - }; - }); - - items = await Promise.all( - items.map((item) => - ctx.cache.tryGet(item.link, async () => { - const detailResponse = await got({ - method: 'get', - url: item.link, - }); - - const content = cheerio.load(detailResponse.data); - content('.broadcast-container').remove(); - - item.description += content('.article-source').html() ?? ''; - item.description += content('#articleContent').html(); - item.title = content('title').text(); - item.author = content('meta[name="author"]').attr('content'); - item.pubDate = timezone(parseDate(content('.article-time').text()), +8); - - return item; - }) - ) - ); - - ctx.state.data = { - title: `广州日报新花城 - ${title}`, - link: currentUrl, - item: items, - }; -}; diff --git a/lib/v2/gzdaily/maintainer.js b/lib/v2/gzdaily/maintainer.js index 67adb75ff..2bb3810c3 100644 --- a/lib/v2/gzdaily/maintainer.js +++ b/lib/v2/gzdaily/maintainer.js @@ -1,4 +1,3 @@ module.exports = { '/app/:column?': ['TimWu007'], - '/cmc/:channel?': ['TimWu007'], }; diff --git a/lib/v2/gzdaily/radar.js b/lib/v2/gzdaily/radar.js index 638a5f826..c4a0174b8 100644 --- a/lib/v2/gzdaily/radar.js +++ b/lib/v2/gzdaily/radar.js @@ -9,14 +9,4 @@ module.exports = { }, ], }, - 'gz-cmc.com': { - _name: '广州日报', - huacheng: [ - { - title: '新花城(广州市融媒体中心)', - docs: 'https://docs.rsshub.app/traditional-media.html#guang-zhou-ri-bao', - source: ['/'], - }, - ], - }, }; diff --git a/lib/v2/gzdaily/router.js b/lib/v2/gzdaily/router.js index 578df19de..bd1c1bc53 100644 --- a/lib/v2/gzdaily/router.js +++ b/lib/v2/gzdaily/router.js @@ -1,4 +1,3 @@ module.exports = (router) => { router.get('/app/:column?', require('./app')); - router.get('/cmc/:channel?', require('./cmc')); };