diff --git a/assets/radar-rules.js b/assets/radar-rules.js index 4eceeeb24f841c..64ebc195579189 100644 --- a/assets/radar-rules.js +++ b/assets/radar-rules.js @@ -27,21 +27,6 @@ { title: '仓库 Contributors', docs: 'https://docs.rsshub.app/programming.html#github', source: ['/:user/:repo/graphs/contributors', '/:user/:repo'], target: '/github/contributors/:user/:repo' }, ], }, - 'ximalaya.com': { - _name: '喜马拉雅', - '.': [ - { - title: '专辑', - docs: 'https://docs.rsshub.app/multimedia.html#xi-ma-la-ya', - source: '/:type/:id', - target: (params) => { - if (parseInt(params.id) + '' === params.id) { - return '/ximalaya/:type/:id/'; - } - }, - }, - ], - }, 'algocasts.io': { _name: 'AlgoCasts', '.': [{ title: '视频更新', docs: 'https://docs.rsshub.app/programming.html#algocasts', source: '/episodes', target: '/algocasts' }] }, 'soulapp.cn': { _name: 'Soul', '.': [{ title: '瞬间更新', docs: 'https://docs.rsshub.app/social-media.html#soul' }] }, 'anime1.me': { diff --git a/docs/en/traditional-media.md b/docs/en/traditional-media.md index 463e8969693e26..d6cee7a291d6a7 100644 --- a/docs/en/traditional-media.md +++ b/docs/en/traditional-media.md @@ -242,6 +242,36 @@ Support all channels, refer to [CNBC RSS feeds](https://www.cnbc.com/rss-feeds/) +## DNA India + +### News + + + +Categories: + +| Headlines | Explainer | India | Entertainment | Sports | Viral | Lifestyle | Education | Business | World | +| --------- | --------- | ----- | ------------- | ------ | ----- | --------- | --------- | -------- | ----- | +| headlines | explainer | india | entertainment | sports | viral | lifestyle | education | business | world | + + + +### Topic + + + +Topics: + +|DNA verified| +|------------| +|dna-verified| + +::: tip Topic +See the URL for `https://www.dnaindia.com/topic/dna-verified` for the subdomain `topic` +::: + + + ## Financial Times ### myFT personal RSS diff --git a/lib/radar-rules.js b/lib/radar-rules.js index a6108a586e36de..be8d25579424c0 100644 --- a/lib/radar-rules.js +++ b/lib/radar-rules.js @@ -1,19 +1,4 @@ module.exports = { - 'ximalaya.com': { - _name: '喜马拉雅', - '.': [ - { - title: '专辑', - docs: 'https://docs.rsshub.app/multimedia.html#xi-ma-la-ya', - source: '/:type/:id', - target: (params) => { - if (parseInt(params.id) + '' === params.id) { - return '/ximalaya/:type/:id/'; - } - }, - }, - ], - }, 'algocasts.io': { _name: 'AlgoCasts', '.': [ diff --git a/lib/router.js b/lib/router.js index 11524bf9612abc..1e91db8ab63b09 100644 --- a/lib/router.js +++ b/lib/router.js @@ -246,8 +246,8 @@ router.get('/yande.re/post/popular_recent/:period', lazyloadRouteHandler('./rout // router.get('/3dm/news', lazyloadRouteHandler('./routes/3dm/news_center')); // 喜马拉雅 -router.get('/ximalaya/:type/:id/:all?', lazyloadRouteHandler('./routes/ximalaya/album')); -router.get('/ximalaya/:type/:id/:all/:shownote?', lazyloadRouteHandler('./routes/ximalaya/album')); +// router.get('/ximalaya/:type/:id/:all?', lazyloadRouteHandler('./routes/ximalaya/album')); +// router.get('/ximalaya/:type/:id/:all/:shownote?', lazyloadRouteHandler('./routes/ximalaya/album')); // EZTV router.get('/eztv/torrents/:imdb_id', lazyloadRouteHandler('./routes/eztv/imdb')); diff --git a/lib/v2/bilibili/vsearch.js b/lib/v2/bilibili/vsearch.js index fb5f0d1f0bb74c..d9d913b30023b5 100644 --- a/lib/v2/bilibili/vsearch.js +++ b/lib/v2/bilibili/vsearch.js @@ -4,11 +4,12 @@ const { parseDate } = require('@/utils/parse-date'); const utils = require('./utils'); const { CookieJar } = require('tough-cookie'); const cookieJar = new CookieJar(); +const { queryToBoolean } = require('@/utils/readable-social'); module.exports = async (ctx) => { const kw = ctx.params.kw; const order = ctx.params.order || 'pubdate'; - const disableEmbed = ctx.params.disableEmbed; + const disableEmbed = queryToBoolean(ctx.params.disableEmbed); const kw_url = encodeURIComponent(kw); const tids = ctx.params.tid ?? 0; diff --git a/lib/v2/dnaindia/category.js b/lib/v2/dnaindia/category.js new file mode 100644 index 00000000000000..c7c54264c9a681 --- /dev/null +++ b/lib/v2/dnaindia/category.js @@ -0,0 +1,66 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const timezone = require('@/utils/timezone'); +const logger = require('@/utils/logger'); + +module.exports = async (ctx) => { + const { category, topic } = ctx.params; + const baseUrl = 'https://www.dnaindia.com'; + let route; + if (category) { + route = `/${category}`; + } else if (topic) { + route = `/topic/${topic}`; + } else { + logger.error('Invalid URL'); + } + const { data: response } = await got(`${baseUrl}${route}`); + const $ = cheerio.load(response); + + const listItems = $('div.col-lg-6 div.list-news') + .toArray() + .map((item) => { + item = $(item); + const a = item.find('div.explainer-subtext a'); + return { + title: a.text(), + link: `${baseUrl}${a.attr('href')}`, + }; + }); + + const items = await Promise.all( + listItems.map((item) => + ctx.cache.tryGet(item.link, async () => { + const { data: response } = await got(item.link); + const $ = cheerio.load(response); + item.itunes_item_image = $('div.article-img img').attr('src'); + item.category = $('div.tags ul li') + .toArray() + .map((item) => $(item).find('a').text()); + const time = $('p.dna-update').text().split('Updated:')[1]; + item.pubDate = timezone(parseDate(time, 'MMMDD,YYYY,hh:mmA'), +5.5); + item.author = 'DNA Web Team'; + item.description = $('div.article-description') + .clone() + .children('div') + .remove() + .end() + .toArray() + .map((element) => $(element).html()) + .join(''); + return item; + }) + ) + ); + + ctx.state.data = { + title: 'DNA India', + link: baseUrl, + item: items, + description: 'Latest News on dnaIndia.com', + logo: 'https://cdn.dnaindia.com/sites/all/themes/dnaindia/favicon-1016.ico', + icon: 'https://cdn.dnaindia.com/sites/all/themes/dnaindia/favicon-1016.ico', + language: 'en-us', + }; +}; diff --git a/lib/v2/dnaindia/maintainer.js b/lib/v2/dnaindia/maintainer.js new file mode 100644 index 00000000000000..047115429102d0 --- /dev/null +++ b/lib/v2/dnaindia/maintainer.js @@ -0,0 +1,4 @@ +module.exports = { + '/:category': ['Rjnishant530'], + '/topic/:topic': ['Rjnishant530'], +}; diff --git a/lib/v2/dnaindia/radar.js b/lib/v2/dnaindia/radar.js new file mode 100644 index 00000000000000..a4edcd2c1700c9 --- /dev/null +++ b/lib/v2/dnaindia/radar.js @@ -0,0 +1,19 @@ +module.exports = { + 'dnaindia.com': { + _name: 'DNA India', + '.': [ + { + title: 'News', + docs: 'https://docs.rsshub.app/en/traditional-media.html#dna-india', + source: ['/:category'], + target: '/dnaindia/:category', + }, + { + title: 'Topic', + docs: 'https://docs.rsshub.app/en/traditional-media.html#dna-india', + source: ['/topic/:topic'], + target: '/dnaindia/topic/:topic', + }, + ], + }, +}; diff --git a/lib/v2/dnaindia/router.js b/lib/v2/dnaindia/router.js new file mode 100644 index 00000000000000..b7dc590d7572e0 --- /dev/null +++ b/lib/v2/dnaindia/router.js @@ -0,0 +1,4 @@ +module.exports = (router) => { + router.get('/:category', require('./category')); + router.get('/topic/:topic', require('./category')); +}; diff --git a/lib/routes/ximalaya/album.js b/lib/v2/ximalaya/album.js similarity index 82% rename from lib/routes/ximalaya/album.js rename to lib/v2/ximalaya/album.js index 066ab3e9c7bb27..197d2d11440b73 100644 --- a/lib/routes/ximalaya/album.js +++ b/lib/v2/ximalaya/album.js @@ -3,6 +3,7 @@ const cheerio = require('cheerio'); const { getUrl, getRandom16 } = require('./utils'); const baseUrl = 'https://www.ximalaya.com'; const config = require('@/config').value; +const { parseDate } = require('@/utils/parse-date'); // Find category from: https://help.apple.com/itc/podcasts_connect/?lang=en#/itc9267a2f12 const categoryDict = { @@ -46,8 +47,8 @@ async function parseAlbumData(category, album_id) { // 解析网页版的 HTML 获取该专辑的信息 // 这里的 {category} 并不重要,系统会准确的返回该 id 对应专辑的信息 // 现在 {category} 必须要精确到大的类别 - // https://www.ximalaya.com/{category}/{album_id}/ - const response = await got(`https://www.ximalaya.com/${category}/${album_id}/`); + // https://www.ximalaya.com/{category}/{album_id} + const response = await got(`${baseUrl}/${category}/${album_id}`); const data = response.body; const $ = cheerio.load(data); const stateElement = $('script') @@ -87,25 +88,27 @@ module.exports = async (ctx) => { const albumData = await parseAlbumData(type, id); - const isPaid = albumData.store.AlbumDetailPage.albumPageMainInfo.isPaid; + const { albumPageMainInfo, currentCategory, anchorInfo } = albumData?.store?.AlbumDetailPage || {}; - const authorInfo = albumData.store.AlbumDetailPage.anchorInfo; // 作者数据 + const isPaid = albumPageMainInfo.isPaid; + + const authorInfo = anchorInfo; // 作者数据 const author = authorInfo.nickName; - const albumInfo = albumData.store.AlbumDetailPage.albumPageMainInfo; // 专辑数据 + const albumInfo = albumPageMainInfo; // 专辑数据 const albumTitle = albumInfo.albumTitle; // 专辑标题 const albumCover = 'http:' + albumInfo.cover.split('!')[0]; const albumIntro = albumInfo.detailRichIntro; // 专辑介绍 - const categoryInfo = albumData.store.AlbumDetailPage.currentCategory; - const albumCategory = categoryInfo.categoryTitle; // 专辑分类名字 - const albumUrl = '/' + categoryInfo.categoryPinyin + '/' + id + '/'; + const categoryInfo = currentCategory; + const albumCategory = categoryInfo?.categoryTitle || albumPageMainInfo.categoryTitle; // 专辑分类名字 + const albumUrl = '/' + (categoryInfo?.categoryPinyin || type) + '/' + id + '/'; // 没有 categoryPinyin 这个字段了,用 type 兼容一下 // sort 为 1 时是降序 // const isAsc = albumData.store.AlbumDetailTrackList.sort === 0; // 喜马拉雅的 API 的 query 参数 isAsc=0 时才是升序,不写就是降序。 const trackInfoApi = `http://mobile.ximalaya.com/mobile/v1/album/track/?albumId=${id}&pageSize=${pageSize}&pageId=`; - const trackInfoResponse = await got.get(trackInfoApi + '1'); + const trackInfoResponse = await got(trackInfoApi + '1'); const maxPageId = trackInfoResponse.data.data.maxPageId; // 最大页数 let playList = trackInfoResponse.data.data.list; @@ -114,22 +117,22 @@ module.exports = async (ctx) => { const promises = []; for (let i = 2; i <= maxPageId; i++) { // string + number -> string - promises.push(got.get(trackInfoApi + i)); + promises.push(got(trackInfoApi + i)); } const responses = await Promise.all(promises); - for (let j = 0; j < responses.length; j++) { - playList = playList.concat(responses[j].data.data.list); + for (const j of responses) { + playList = playList.concat(j.data.data.list); } } await Promise.all( playList.map(async (item) => { const link = baseUrl + albumUrl + item.trackId; - item.desc = await ctx.cache.tryGet(shouldShowNote.toString() + 'trackRichInfo' + link, async () => { + item.desc = await ctx.cache.tryGet('ximalaya:' + shouldShowNote.toString() + 'trackRichInfo' + link, async () => { let _desc; if (shouldShowNote) { const trackRichInfoApi = `https://mobile.ximalaya.com/mobile-track/richIntro?trackId=${item.trackId}`; - const trackRichInfoResponse = await got.get(trackRichInfoApi); + const trackRichInfoResponse = await got(trackRichInfoApi); _desc = trackRichInfoResponse.data.richIntro; } if (!_desc) { @@ -146,10 +149,8 @@ module.exports = async (ctx) => { await Promise.all( playList.map(async (item) => { const trackPayInfoApi = `https://mpay.ximalaya.com/mobile/track/pay/${item.trackId}/?device=pc`; - const data = await ctx.cache.tryGet('trackPayInfo' + trackPayInfoApi, async () => { - const trackPayInfoResponse = await got({ - method: 'get', - url: trackPayInfoApi, + const data = await ctx.cache.tryGet('ximalaya:trackPayInfo' + trackPayInfoApi, async () => { + const trackPayInfoResponse = await got(trackPayInfoApi, { headers: { 'user-agent': 'ting_6.7.9(GM1900,Android29)', cookie: `1&_device=android&${randomToken}&6.7.9;1&_token=${token}`, @@ -178,7 +179,7 @@ module.exports = async (ctx) => { const trackId = item.trackId; const itunesItemImage = item.coverLarge ? item.coverLarge : albumCover; const link = baseUrl + albumUrl + trackId; - const pubDate = new Date(item.createdAt).toUTCString(); + const pubDate = parseDate(item.createdAt, 'x'); const duration = item.duration; // 时间长度:单位(秒) const enclosureUrl = item.playPathAacv224 || item.playPathAacv164; diff --git a/lib/v2/ximalaya/maintainer.js b/lib/v2/ximalaya/maintainer.js new file mode 100644 index 00000000000000..8f461073a46694 --- /dev/null +++ b/lib/v2/ximalaya/maintainer.js @@ -0,0 +1,4 @@ +module.exports = { + '/:type/:id/:all?': ['lengthmin', 'jjeejj', 'prnake'], + '/:type/:id/:all/:shownote?': ['lengthmin', 'jjeejj', 'prnake'], +}; diff --git a/lib/v2/ximalaya/radar.js b/lib/v2/ximalaya/radar.js new file mode 100644 index 00000000000000..567dfafc61783f --- /dev/null +++ b/lib/v2/ximalaya/radar.js @@ -0,0 +1,17 @@ +module.exports = { + 'ximalaya.com': { + _name: '喜马拉雅', + '.': [ + { + title: '专辑', + docs: 'https://docs.rsshub.app/multimedia.html#xi-ma-la-ya', + source: '/:type/:id', + target: (params) => { + if (parseInt(params.id) + '' === params.id) { + return '/ximalaya/:type/:id'; + } + }, + }, + ], + }, +}; diff --git a/lib/v2/ximalaya/router.js b/lib/v2/ximalaya/router.js new file mode 100644 index 00000000000000..dfda7356b60644 --- /dev/null +++ b/lib/v2/ximalaya/router.js @@ -0,0 +1,4 @@ +module.exports = (router) => { + router.get('/:type/:id/:all?', require('./album')); + router.get('/:type/:id/:all/:shownote?', require('./album')); +}; diff --git a/lib/routes/ximalaya/utils.js b/lib/v2/ximalaya/utils.js similarity index 89% rename from lib/routes/ximalaya/utils.js rename to lib/v2/ximalaya/utils.js index dc599fe256aac9..1800cfa3b27158 100644 --- a/lib/routes/ximalaya/utils.js +++ b/lib/v2/ximalaya/utils.js @@ -78,11 +78,11 @@ const getParams = (ep) => { let a3 = 0; o = 0; - for (let u = 0; u < a2.length; u++) { + for (const u of a2) { a3 = (a3 + 1) % 256; o = (o + r1[a3]) % 256; [r1[a3], r1[o]] = [r1[o], r1[a3]]; - i += String.fromCharCode(a2[u] ^ r1[(r1[a3] + r1[o]) % 256]); + i += String.fromCharCode(u ^ r1[(r1[a3] + r1[o]) % 256]); } i = i.split('-'); return { @@ -112,10 +112,11 @@ const getPath = (seed, fileId) => { const getUrl = (r) => { const params = getParams(r.ep); - const paramsArray = []; params.duration = r.duration; - Object.keys(params).forEach((key) => params[key] && paramsArray.push(`${key}=${params[key]}`)); - const url = 'https://audiopay.cos.xmcdn.com/download/' + r.apiVersion + '/' + getPath(r.seed, r.fileId) + '?' + paramsArray.join('&'); + const paramsArray = Object.keys(params) + .filter((key) => params[key]) + .map((key) => `${key}=${params[key]}`); + const url = `https://audiopay.cos.xmcdn.com/download/${r.apiVersion}/${getPath(r.seed, r.fileId)}?${paramsArray.join('&')}`; return url; }; diff --git a/lib/v2/zhihu/answers.js b/lib/v2/zhihu/answers.js index dd43a0cd08f1e3..65a00cd8730c8b 100644 --- a/lib/v2/zhihu/answers.js +++ b/lib/v2/zhihu/answers.js @@ -20,7 +20,7 @@ module.exports = async (ctx) => { if (name === '知乎用户') { const userProfile = await ctx.cache.tryGet(`zhihu:profile:${id}`, async () => { - const apiPath = `/api/v4/profile/${id}/infinity`; + const apiPath = `/api/v4/members/${id}`; const { data } = await got({ method: 'get', @@ -30,7 +30,7 @@ module.exports = async (ctx) => { Referer: `https://www.zhihu.com/people/${id}`, }, }); - return data.data; + return data; }); name = userProfile.name; }