diff --git a/assets/radar-rules.js b/assets/radar-rules.js index 5a6d0d3a72..50efe73161 100644 --- a/assets/radar-rules.js +++ b/assets/radar-rules.js @@ -610,6 +610,28 @@ }, ], }, + 'mhgui.com': { + _name: '漫画柜镜像站', + www: [ + { + title: '漫画更新', + docs: 'https://docs.rsshub.app/anime.html#kan-man-hua-jing-xiang-zhan', + source: '/comic/:id/', + target: '/mhgui/comic/:id', + }, + ], + }, + 'tw.manhuagui.com': { + _name: '漫画柜台湾', + www: [ + { + title: '漫画更新', + docs: 'https://docs.rsshub.app/anime.html#kan-man-hua-tai-wan', + source: '/comic/:id/', + target: '/twmanhuagui/comic/:id', + }, + ], + }, 'pgyer.com': { _name: '蒲公英应用分发', www: [ @@ -1888,28 +1910,34 @@ _name: '站酷', www: [ { - title: '全部推荐', + title: '发现', docs: 'https://docs.rsshub.app/design.html#zhan-ku', source: '', - target: '/zcool/recommenda/all', + target: '/zcool/discover', }, { - title: '首页推荐', + title: '发现 - 精选 - 全部推荐', docs: 'https://docs.rsshub.app/design.html#zhan-ku', source: '', - target: '/zcool/recommenda/home', + target: '/zcool/discover/all', }, { - title: '编辑推荐', + title: '发现 - 精选 - 首页推荐', docs: 'https://docs.rsshub.app/design.html#zhan-ku', source: '', - target: '/zcool/recommenda/home', + target: '/zcool/discover/home', }, { - title: '文章推荐', + title: '发现 - 精选 - 编辑精选', docs: 'https://docs.rsshub.app/design.html#zhan-ku', source: '', - target: '/zcool/recommenda/article', + target: '/zcool/discover/home', + }, + { + title: '发现 - 精选 - 文章 - 编辑精选', + docs: 'https://docs.rsshub.app/design.html#zhan-ku', + source: '', + target: '/zcool/discover/article', }, { title: '作品榜单', @@ -2007,12 +2035,18 @@ { title: '视频 - 播放列表', docs: 'https://docs.rsshub.app/multimedia.html#teng-xun-shi-pin', - source: '/detail/:type/:id', + source: '/x/cover/:id', target: (params) => { const id = params.id.match('(.*).html')[1]; return id ? `/tencentvideo/playlist/${id}` : ''; }, }, + { + title: '视频 - 播放列表', + docs: 'https://docs.rsshub.app/multimedia.html#teng-xun-shi-pin', + source: '/x/cover/:id/:detail', + target: '/tencentvideo/playlist/:id', + }, ], }, 'javbus.com': { @@ -3007,4 +3041,14 @@ }, ], }, + 'zyshow.net': { + www: [ + { + title: '', + docs: 'https://docs.rsshub.app/game.html#lv-fa-shi-ying-di', + source: '/:name/', + target: '/zyshow/:name', + }, + ], + }, }); diff --git a/docs/anime.md b/docs/anime.md index 89ae2d4861..81e946be5d 100644 --- a/docs/anime.md +++ b/docs/anime.md @@ -292,7 +292,7 @@ pageClass: routes ### 风之动漫 - + ## 海猫吧 @@ -306,6 +306,18 @@ pageClass: routes +## 看漫画镜像站 + +### 漫画更新 + + + +## 看漫画台湾 + +### 漫画更新 + + + ## 漫画 DB ### 漫画 DB diff --git a/docs/design.md b/docs/design.md index 5703dca277..db59916b53 100644 --- a/docs/design.md +++ b/docs/design.md @@ -160,15 +160,153 @@ Behance 用户主页 URL 获取用户名,如 + 推荐类型 -| all | home | edit | article | +| all | home | editor | article | | -------- | -------- | -------- | -------- | -| 全部推荐 | 首页推荐 | 编辑推荐 | 文章推荐 | +| 全部推荐 | 首页推荐 | 编辑精选 | 文章推荐 | + + + +### 发现(+ 查询参数) + + + +在 [站酷发现页](https://www.zcool.com.cn/discover) 中选择好所有可选的查询参数后会跳转到对应搜索结果页面。此时地址栏 `https://www.zcool.com.cn/discover/` 后的字段即为查询参数。 + +如:选择 **精选** 分类下的 **运营设计** 子分类后,选择 **编辑精选**,默认 **视频** 取消勾选,默认 **城市** 和 **学校** 留空即全部,就会跳转到链接: + + + +此时其查询参数为 `cate=0&subCate=617&hasVideo=0&city=0&college=0&recommendLevel=2&sort=9`。其对应的路由即 [`/zcool/discover/cate=0&subCate=617&hasVideo=0&city=0&college=0&recommendLevel=2&sort=9`](https://rsshub.app/zcool/discover/cate=0&subCate=617&hasVideo=0&city=0&college=0&recommendLevel=2&sort=9) + + + +### 发现 + + + +查看 **精选** 分类下的全部内容,其他参数选择默认,可直接使用路由 [`/zcool/discover/0`](https://rsshub.app/zcool/discover/0) + +查看 **精选** 分类下的 **运营设计** 子分类全部内容,其他参数选择默认,可直接使用路由 [`/zcool/discover/0/617`](https://rsshub.app/zcool/discover/0/617) + +在 **精选** 分类下的 **运营设计** 子分类全部内容基础上,筛选出有 **视频**,可直接使用路由 [`/zcool/discover/0/617/1`](https://rsshub.app/zcool/discover/0/617/1) + +在 **精选** 分类下的 **运营设计** 子分类全部内容基础上,筛选出有 **视频**,且城市选择 **北京**,可直接使用路由 [`/zcool/discover/0/617/1/北京`](https://rsshub.app/zcool/discover/0/617/1/北京) + +::: tip 提示 + +下方仅提供 **分类及其子分类** 参数的代码。**学校** 参数的代码可以在 [站酷发现页](https://www.zcool.com.cn/discover) 中选择跳转后,从浏览器地址栏中找到。 + +::: + +分类 cate + +| 精选 | 平面 | 插画 | UI | 网页 | 摄影 | 三维 | 影视 | 空间 | 工业 / 产品 | 动漫 | 纯艺术 | 手工艺 | 服装 | 其他 | +| ---- | ---- | ---- | -- | ---- | ---- | ---- | ---- | ---- | ----------- | ---- | ------ | ------ | ---- | ---- | +| 0 | 8 | 1 | 17 | 607 | 33 | 24 | 610 | 609 | 499 | 608 | 612 | 611 | 613 | 44 | + +子分类 subCate + +精选 0 + +| 运营设计 | 包装 | 动画 / 影视 | 人像摄影 | 商业插画 | 电商 | APP 界面 | 艺术插画 | 家装设计 | 海报 | 文章 | +| -------- | ---- | ----------- | -------- | -------- | ---- | -------- | -------- | -------- | ---- | ------ | +| 617 | 9 | 30 | 34 | 2 | 616 | 757 | 292 | 637 | 10 | 809824 | + +平面 8 + +| 包装 | 海报 | 品牌 | IP 形象 | 字体 / 字形 | Logo | 书籍 / 画册 | 宣传物料 | 图案 | 信息图表 | PPT/Keynote | 其他平面 | 文章 | +| ---- | ---- | ---- | ------- | ----------- | ---- | ----------- | -------- | ---- | -------- | ----------- | -------- | ---- | +| 9 | 10 | 15 | 779 | 14 | 13 | 12 | 534 | 624 | 625 | 626 | 11 | 809 | + +插画 1 + +| 商业插画 | 概念设定 | 游戏原画 | 绘本 | 儿童插画 | 艺术插画 | 创作习作 | 新锐潮流插画 | 像素画 | 文章 | +| -------- | -------- | -------- | ---- | -------- | -------- | -------- | ------------ | ------ | ---- | +| 2 | 5 | 685 | 631 | 684 | 292 | 7 | 3 | 4 | 819 | + +UI 17 + +| APP 界面 | 游戏 UI | 软件界面 | 图标 | 主题 / 皮肤 | 交互 / UE | 动效设计 | 闪屏 / 壁纸 | 其他 UI | 文章 | +| -------- | ------- | -------- | ---- | ----------- | --------- | -------- | ----------- | ------- | ---- | +| 757 | 692 | 621 | 20 | 19 | 623 | 797 | 21 | 23 | 822 | + +网页 607 + +| 电商 | 企业官网 | 游戏 / 娱乐 | 运营设计 | 移动端网页 | 门户网站 | 个人网站 | 其他网页 | 文章 | +| ---- | -------- | ----------- | -------- | ---------- | -------- | -------- | -------- | ---- | +| 616 | 614 | 693 | 617 | 777 | 615 | 618 | 620 | 823 | + +摄影 33 + +| 人像摄影 | 风光摄影 | 人文 / 纪实摄影 | 美食摄影 | 产品摄影 | 环境 / 建筑摄影 | 时尚 / 艺术摄影 | 修图 / 后期 | 宠物摄影 | 婚礼摄影 | 其他摄影 | 文章 | +| -------- | -------- | --------------- | -------- | -------- | --------------- | --------------- | ----------- | -------- | -------- | -------- | ---- | +| 34 | 35 | 36 | 825 | 686 | 38 | 800 | 687 | 40 | 808 | 43 | 810 | + +三维 24 + +| 动画 / 影视 | 机械 / 交通 | 人物 / 生物 | 产品 | 场景 | 建筑 / 空间 | 其他三维 | 文章 | +| ----------- | ----------- | ----------- | ---- | ---- | ----------- | -------- | ---- | +| 30 | 25 | 27 | 807 | 26 | 29 | 32 | 818 | + +影视 610 + +| 短片 | Motion Graphic | 宣传片 | 影视后期 | 栏目片头 | MV | 设定 / 分镜 | 其他影视 | 文章 | +| ---- | -------------- | ------ | -------- | -------- | --- | ----------- | -------- | ---- | +| 645 | 649 | 804 | 646 | 647 | 644 | 650 | 651 | 817 | + +空间 609 + +| 家装设计 | 酒店餐饮设计 | 商业空间设计 | 建筑设计 | 舞台美术 | 展陈设计 | 景观设计 | 其他空间 | 文章 | +| -------- | ------------ | ------------ | -------- | -------- | -------- | -------- | -------- | ---- | +| 637 | 811 | 641 | 636 | 638 | 639 | 640 | 642 | 812 | + +工业 / 产品 499 + +| 生活用品 | 电子产品 | 交通工具 | 工业用品 / 机械 | 人机交互 | 玩具 | 其他工业 / 产品 | 文章 | +| -------- | -------- | -------- | --------------- | -------- | ---- | --------------- | ---- | +| 508 | 506 | 509 | 511 | 510 | 689 | 514 | 813 | + +动漫 608 + +| 短篇 / 格漫 | 中 / 长篇漫画 | 网络表情 | 单幅漫画 | 动画片 | 其他动漫 | 文章 | +| ----------- | ------------- | -------- | -------- | ------ | -------- | ---- | +| 628 | 629 | 632 | 627 | 633 | 635 | 820 | + +纯艺术 612 + +| 绘画 | 雕塑 | 书法 | 实验艺术 | 文章 | +| ---- | ---- | ---- | -------- | ---- | +| 659 | 662 | 668 | 657 | 821 | + +手工艺 611 + +| 工艺品设计 | 手办 / 模玩 | 首饰设计 | 其他手工艺 | 文章 | +| ---------- | ----------- | -------- | ---------- | ---- | +| 654 | 656 | 756 | 658 | 816 | + +服装 613 + +| 休闲 / 流行服饰 | 正装 / 礼服 | 传统 / 民族服饰 | 配饰 | 鞋履设计 | 儿童服饰 | 其他服装 | 文章 | +| --------------- | ----------- | --------------- | ---- | -------- | -------- | -------- | ---- | +| 672 | 671 | 814 | 677 | 676 | 673 | 680 | 815 | + +其他 44 + +| 文案 / 策划 | VR 设计 | 独立游戏 | 其他 | 文章 | +| ----------- | ------- | -------- | ---- | ---- | +| 417 | 798 | 683 | 45 | 824 | + +推荐等级 recommendLevel + +| 全部 | 编辑精选 | 首页推荐 | 全部推荐 | +| ---- | -------- | -------- | -------- | +| 0 | 2 | 3 | 1 | @@ -195,13 +333,3 @@ Behance 用户主页 URL 获取用户名,如 - -### 发现 - - - -在 [发现页](https://www.zcool.com.cn/discover) 中选择查询参数后会跳转到对应搜索结果页面。此时地址栏 `https://www.zcool.com.cn/discover/` 后的字段即为查询参数。 - -如: 查询参数为 `0!0!0!0!0!!!!2!-1!1` - - diff --git a/docs/en/game.md b/docs/en/game.md index f2fd36bbe6..440faf119c 100755 --- a/docs/en/game.md +++ b/docs/en/game.md @@ -158,6 +158,12 @@ Compatible with Product with an URL like +## ProjectSekai | プロセカ + +### News + + + ## Steam ### Steam search diff --git a/docs/en/new-media.md b/docs/en/new-media.md index 3d58ff4cc5..c72e3908b8 100644 --- a/docs/en/new-media.md +++ b/docs/en/new-media.md @@ -175,6 +175,12 @@ Compared to the official one, the RSS feed generated by RSSHub not only has more +## Harvard Health Publishing + +### Harvard Health Blog + + + ## iDownloadBlog ### iDownloadBlog diff --git a/docs/en/program-update.md b/docs/en/program-update.md index 6bb7b21f99..105b252de2 100644 --- a/docs/en/program-update.md +++ b/docs/en/program-update.md @@ -259,6 +259,18 @@ Refer to [#minecraft](/en/game.html#minecraft) 见 [#playstation](/game.html#playstation) +## Potplayer + +### Version History + + + +| 한국어 | 中文 (简体) | 中文 (繁体) | ENGLISH | Українська | РУССКИЙ | Polski | +| ------ | ----------- | ----------- | ------- | ---------- | ------- | ------ | +| ko | zh_CN | zh_TW | en | uk | ru | pl | + + + ## QNAP ### Release Notes diff --git a/docs/en/programming.md b/docs/en/programming.md index 9a7b3b93d7..560c2e447d 100644 --- a/docs/en/programming.md +++ b/docs/en/programming.md @@ -111,7 +111,7 @@ For instance, the `/github/topics/framework/l=php&o=desc&s=stars` route will gen ### Explore - + | Trending | Most stars | All | | -------- | ---------- | --- | @@ -119,6 +119,15 @@ For instance, the `/github/topics/framework/l=php&o=desc&s=stars` route will gen +### Releases + + + +### Tags + + + + ## Hacker News ### Section diff --git a/docs/finance.md b/docs/finance.md index 589b939c09..892c1f1d92 100644 --- a/docs/finance.md +++ b/docs/finance.md @@ -199,6 +199,10 @@ pageClass: routes +### 股票评论 + + + ## 证券时报网 ### 要闻 diff --git a/docs/game.md b/docs/game.md index 729e61317b..383336d490 100644 --- a/docs/game.md +++ b/docs/game.md @@ -530,6 +530,12 @@ Example:`https://www.iyingdi.com/tz/people/55547` ,id 是 `55547` +## 世界计划 多彩舞台 | ProjectSekai | プロセカ + +### 公告 + + + ## 王者荣耀 ### 新闻中心 diff --git a/docs/government.md b/docs/government.md index 2855138c78..57df953d08 100644 --- a/docs/government.md +++ b/docs/government.md @@ -668,3 +668,15 @@ pageClass: routes ### 审查调查 + +## 德阳考试中心 + +### 考试新闻 + + + +| 新闻中心 | 公务员考试 | 事业单位 | (职)业资格、职称考试 | 其他 | +| :------: | :------: | :------: |:------: |:------: | +| all | gwy | sydw | zyzc | other | + + diff --git a/docs/multimedia.md b/docs/multimedia.md index a8bbbe9b42..93b27c1d5a 100644 --- a/docs/multimedia.md +++ b/docs/multimedia.md @@ -1134,3 +1134,9 @@ Tiny Tiny RSS 会给所有 iframe 元素添加 `sandbox="allow-scripts"` 属性 例如,路由 `/zimuzu/top/week/movie` 应该输出 的排行榜单 + +## 综艺秀([www.zyshow.net)](http://www.zyshow.net)) + +### 综艺 + + diff --git a/docs/new-media.md b/docs/new-media.md index c2d5ed4788..17b6aafbd5 100644 --- a/docs/new-media.md +++ b/docs/new-media.md @@ -114,6 +114,18 @@ pageClass: routes +## CBNData + +### 看点 + + + +| 看点 | 餐饮零售 | 美妆个护 | 服饰鞋包 | 家电数码 | 宠物 | 营销 | +| ---- | -------- | -------- | -------- | -------- | ---- | ---- | +| | 2560 | 1 | 2559 | 59 | 2419 | 2484 | + + + ## cfan ### 新闻 @@ -288,6 +300,12 @@ Tag +## Harvard Health Publishing + +### Harvard Health Blog + + + ## HKEPC ### HKEPC 電腦領域 @@ -581,6 +599,22 @@ IPFS 网关有可能失效,那时候换成其他网关。 +## TANC 艺术新闻 + +### 分类 + + + +| INDEX 首页 | ENGLISH 英文版 | NEWS 新闻 | MUSEUM 博物馆 | EXHIBITIONS 展览 | +| ---------- | -------------- | --------- | ------------- | ---------------- | +| | english | news | museum | exhibitions | + +| COMMENTS 评论 | FEATURE 特写 | INTERVIEW 专访 | VIDEO 影像之选 | ART MARKET 艺术市场 | +| ------------- | ------------ | -------------- | -------------- | ------------------- | +| comments | feature | interview | video | art-market | + + + ## The Brain ### Blog @@ -1788,6 +1822,26 @@ column 为 third 时可选的 category: +## 人民论坛网 + +### 思想理论 + + + +| 首页 | 独家连线 | 深度原创 | 中外思潮 | 时事洞察 | +| ---- | ---------- | ---------- | -------- | -------- | +| | connection | yuanchuang | sichao | dongcha | + +| 中国声音 | 全球观察 | 思想名人堂 | 学术人生 | +| -------- | -------- | ----------- | -------- | +| shengyin | guancha | mingrentang | xueshu | + +| 前沿理论 | 比较研究 | +| -------- | -------- | +| lilun | yanjiu | + + + ## 人人都是产品经理 ### 热门文章 diff --git a/docs/other.md b/docs/other.md index 271e86d164..babd3206e8 100644 --- a/docs/other.md +++ b/docs/other.md @@ -728,6 +728,46 @@ type 为 all 时,category 参数不支持 cost 和 free +### 创业板项目动态 + + + +类型 + +| IPO | 再融资 | 重大资产重组 | +| --- | ------ | ------------ | +| 1 | 2 | 3 | + +阶段 + +| 全部 | 受理 | 问询 | 上市委会议 | +| ---- | ---- | ---- | ---------- | +| 0 | 10 | 20 | 30 | + +| 提交注册 | 注册结果 | 中止 | 终止 | +| -------- | -------- | ---- | ---- | +| 35 | 40 | 50 | 60 | + +状态 + +| 全部 | 新受理 | 已问询 | 通过 | 未通过 | +| ---- | ------ | ------ | ---- | ------ | +| 0 | 20 | 30 | 45 | 44 | + +| 暂缓审议 | 复审通过 | 复审不通过 | 提交注册 | +| -------- | -------- | ---------- | -------- | +| 46 | 56 | 54 | 60 | + +| 注册生效 | 不予注册 | 补充审核 | 终止注册 | +| -------- | -------- | -------- | -------- | +| 70 | 74 | 78 | 76 | + +| 中止 | 审核不通过 | 撤回 | +| ---- | ---------- | ---- | +| 80 | 90 | 95 | + + + ## 守望先锋 ### 补丁说明 diff --git a/docs/program-update.md b/docs/program-update.md index 79064578ad..2e058e139d 100644 --- a/docs/program-update.md +++ b/docs/program-update.md @@ -308,6 +308,18 @@ pageClass: routes 见 [#playstation](/game.html#playstation) +## Potplayer + +### 版本历史 + + + +| 한국어 | 中文 (简体) | 中文 (繁体) | ENGLISH | Українська | РУССКИЙ | Polski | +| ------ | ----------- | ----------- | ------- | ---------- | ------- | ------ | +| ko | zh_CN | zh_TW | en | uk | ru | pl | + + + ## QNAP ### Release Notes diff --git a/docs/programming.md b/docs/programming.md index a160cabf25..401ada0c33 100644 --- a/docs/programming.md +++ b/docs/programming.md @@ -177,7 +177,7 @@ GitHub 官方也提供了一些 RSS: ### Explore - + | Trending | Most stars | All | | -------- | ---------- | --- | @@ -185,6 +185,14 @@ GitHub 官方也提供了一些 RSS: +### Releases + + + +### Tags + + + ## Go 语言中文网 ### 周刊 diff --git a/docs/traditional-media.md b/docs/traditional-media.md index 075b91afc4..981664ada2 100644 --- a/docs/traditional-media.md +++ b/docs/traditional-media.md @@ -531,11 +531,11 @@ IT・科学 tech_science -无料全文,综合页文章标题添加板块标签。 +无料全文,综合页 (新着・速報) 文章标题补充板块标签。 -| 総合 | 社会 | 政治 | 経済 | スポーツ | 国際 | 科学・IT | 選挙・世論調査 | エンタメ・文化 | 囲碁・将棋 | ライフ | 地域 | 社説 | -| ---- | -------- | -------- | ------- | -------- | ----- | ---------- | -------------- | -------------- | ---------- | ------ | ----- | --------- | -| news | national | politics | economy | sports | world | science | election | culture | igoshougi | life | local | editorial | +| 新着・速報 |   社会 | 政治 | 経済 | スポーツ | 国際 | 科学・IT | 選挙・世論調査 | エンタメ・文化 | 囲碁・将棋 | ライフ | 地域 | 社説 | +| ---------- | -------- | -------- | ------- | -------- | ----- | ---------- | -------------- | -------------- | ---------- | ------ | ----- | --------- | +|  news   | national | politics | economy | sports | world | science | election | culture | igoshougi | life | local | editorial | @@ -740,7 +740,7 @@ category 对应的关键词有 ### 新闻聚合 - + ## 连线 Wired diff --git a/docs/university.md b/docs/university.md index 227cd9a9cc..2f851d0dc1 100644 --- a/docs/university.md +++ b/docs/university.md @@ -817,7 +817,7 @@ category 列表: ### 哈尔滨工业大学(深圳) - 新闻中心 - + | 校区要闻 | 媒体报道 | 通知公告 | 综合新闻 | 校园动态 | 讲座论坛 | 热点专题 | | -------- | -------- | -------- | -------- | -------- | -------- | -------- | @@ -973,6 +973,14 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE_TLS +### 电子与信息学院 - 新闻速递 + + + +::: warning 注意 +由于学院官网对非大陆 IP 的访问存在限制,需自行部署。 +::: + ## 华南师范大学 ### 软件学院通知公告 @@ -1922,6 +1930,20 @@ type 列表: +### 就业创业中心 + + + +栏目类型 + +| 中心通告 | 选调生及公务员 | 国际组织实习 | 新闻资讯 | 活动与讲座 | +| -------- | -------------- | ------------ | -------- | ---------- | +| zxtg | xdsgwy | gjzzsx | xwzx | hdyjz | + +### 电气学院 + + + ## 西北工业大学 ### 翱翔门户 diff --git a/lib/router.js b/lib/router.js index 429f3905f2..de2059e9b1 100644 --- a/lib/router.js +++ b/lib/router.js @@ -493,6 +493,7 @@ router.get('/xueqiu/fund/:id', require('./routes/xueqiu/fund')); router.get('/xueqiu/stock_info/:id/:type?', require('./routes/xueqiu/stock_info')); router.get('/xueqiu/snb/:id', require('./routes/xueqiu/snb')); router.get('/xueqiu/hots', require('./routes/xueqiu/hots')); +router.get('/xueqiu/stock_comments/:id/:titleLength?', require('./routes/xueqiu/stock_comments')); // Greasy Fork router.get('/greasyfork/:language/:domain?', require('./routes/greasyfork/scripts')); @@ -597,7 +598,9 @@ router.get('/novel/zhaishuyuan/:id', require('./routes/novel/zhaishuyuan')); router.get('/weatheralarm/:province?', require('./routes/weatheralarm')); // Gitlab -router.get('/gitlab/explore/:type', require('./routes/gitlab/explore')); +router.get('/gitlab/explore/:type/:host?', require('./routes/gitlab/explore')); +router.get('/gitlab/release/:namespace/:project/:host?', require('./routes/gitlab/release')); +router.get('/gitlab/tag/:namespace/:project/:host?', require('./routes/gitlab/tag')); // 忧郁的loli router.get('/mygalgame', require('./routes/galgame/hhgal')); // 废弃 @@ -1134,6 +1137,9 @@ router.get('/tencentvideo/playlist/:id', require('./routes/tencent/video/playlis // 看漫画 router.get('/manhuagui/comic/:id', require('./routes/manhuagui/comic')); +router.get('/mhgui/comic/:id', require('./routes/mhgui/comic')); +router.get('/twmanhuagui/comic/:id', require('./routes/twmanhuagui/comic')); + // 動漫狂 router.get('/cartoonmad/comic/:id', require('./routes/cartoonmad/comic')); // Vol @@ -2007,11 +2013,11 @@ router.get('/getitfree/search/:keyword?', require('./routes/getitfree/search.js' router.get('/10000link/news/:category?', require('./routes/10000link/news')); // 站酷 -router.get('/zcool/recommend/:type', require('./routes/zcool/recommend')); +router.get('/zcool/discover/:query?/:subCate?/:hasVideo?/:city?/:collage?/:recommendLevel?/:sort?', require('./routes/zcool/discover')); +router.get('/zcool/recommend/:query?/:subCate?/:hasVideo?/:city?/:collage?/:recommendLevel?/:sort?', require('./routes/zcool/discover')); // 兼容老版本 router.get('/zcool/top/:type', require('./routes/zcool/top')); router.get('/zcool/top', require('./routes/zcool/top')); // 兼容老版本 router.get('/zcool/user/:uid', require('./routes/zcool/user')); -router.get('/zcool/discovery/:query?', require('./routes/zcool/discovery')); // 第一财经 router.get('/yicai/brief', require('./routes/yicai/brief.js')); @@ -2160,6 +2166,7 @@ router.get('/sse/disclosure/:query?', require('./routes/sse/disclosure')); router.get('/szse/notice', require('./routes/szse/notice')); router.get('/szse/inquire/:type', require('./routes/szse/inquire')); router.get('/szse/rule', require('./routes/szse/rule')); +router.get('/szse/projectdynamic/:type?/:stage?/:status?', require('./routes/szse/projectdynamic')); // 前端艺术家每日整理&&飞冰早报 router.get('/jskou/:type?', require('./routes/jskou/index')); @@ -2651,6 +2658,8 @@ router.get('/wolley/host/:host', require('./routes/wolley/host')); router.get('/xjtu/gs/tzgg', require('./routes/universities/xjtu/gs/tzgg')); router.get('/xjtu/dean/:subpath+', require('./routes/universities/xjtu/dean')); router.get('/xjtu/international/:subpath+', require('./routes/universities/xjtu/international')); +router.get('/xjtu/job/:subpath?', require('./routes/universities/xjtu/job')); +router.get('/xjtu/ee/:id?', require('./routes/universities/xjtu/ee')); // booksource router.get('/booksource', require('./routes/booksource/index')); @@ -2977,7 +2986,7 @@ router.get('/grubstreet', require('./routes/grubstreet/index')); router.get('/manhuadui/manhua/:name/:serial?', require('./routes/manhuadui/manhua')); // 风之漫画 -router.get('/fzdm/manhua/:id/:nums?', require('./routes/fzdm/manhua')); +router.get('/fzdm/manhua/:id', require('./routes/fzdm/manhua')); // Aljazeera 半岛网 router.get('/aljazeera/news', require('./routes/aljazeera/news')); @@ -3149,7 +3158,7 @@ router.get('/erbingapp/news', require('./routes/erbingapp/news')); router.get('/dsb/area/:area', require('./routes/dsb/area')); // 靠谱新闻 -router.get('/kaopunews/all', require('./routes/kaopunews/all')); +router.get('/kaopunews/:language?', require('./routes/kaopunews')); // Reuters router.get('/reuters/theWire', require('./routes/reuters/theWire')); @@ -3236,6 +3245,9 @@ router.get('/scvtc/xygg', require('./routes/universities/scvtc/xygg')); // 华南理工大学土木与交通学院 router.get('/scut/scet/notice', require('./routes/universities/scut/scet/notice')); +// 华南理工大学电子与信息学院 +router.get('/scut/seie/news_center', require('./routes/universities/scut/seie/news_center')); + // OneJAV router.get('/onejav/:type/:key?', require('./routes/onejav/one')); @@ -4116,10 +4128,34 @@ router.get('/bibgame/:category?/:type?', require('./routes/bibgame/category')); // 澳門特別行政區政府各公共部門獎助貸學金服務平台 router.get('/macau-bolsas/:lang?', require('./routes/macau-bolsas/index')); +// PotPlayer +router.get('/potplayer/update/:language?', require('./routes/potplayer/update')); + +// 综艺秀 +router.get('/zyshow/:name', require('./routes/zyshow')); + // 加美财经 router.get('/caus/:category?', require('./routes/caus')); // 摩点 router.get('/modian/zhongchou/:category?/:sort?/:status?', require('./routes/modian/zhongchou')); +// 世界计划 多彩舞台 feat.初音未来 (ProjectSekai) +router.get('/pjsk/news', require('./routes/pjsk/news')); + +// 人民论坛网 +router.get('/rmlt/idea/:category?', require('./routes/rmlt/idea')); + +// CBNData +router.get('/cbndata/information/:category?', require('./routes/cbndata/information')); + +// TANC 艺术新闻 +router.get('/tanchinese/:category?', require('./routes/tanchinese')); + +// Harvard +router.get('/harvard/health/blog', require('./routes/universities/harvard/health/blog')); + +// dykszx +router.get('/dykszx/news/:type?', require('./routes/dykszx/news')); + module.exports = router; diff --git a/lib/routes/cbndata/information.js b/lib/routes/cbndata/information.js new file mode 100644 index 0000000000..db3bf21d09 --- /dev/null +++ b/lib/routes/cbndata/information.js @@ -0,0 +1,53 @@ +const got = require('@/utils/got'); + +module.exports = async (ctx) => { + const category = ctx.params.category || ''; + + const rootUrl = 'https://www.cbndata.com'; + const apiUrl = `${rootUrl}/api/v3/informations?page=1&per_page=10${category ? `&tag_id=${category}` : ''}`; + + const response = await got({ + method: 'get', + url: apiUrl, + }); + + const list = response.data.data.map((item) => ({ + title: item.id, + link: `${rootUrl}/api/v3/informations/show?id=${item.id}`, + pubDate: Date.parse(item.date), + })); + + const items = await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + + item.link = `${rootUrl}/information/${item.title}`; + + item.title = detailResponse.data.data.title; + item.author = detailResponse.data.data.author; + item.description = detailResponse.data.data.content; + + return item; + }) + ) + ); + + let title = '看点'; + + for (const tag of response.data.home_tags) { + if (tag.id.toString() === category) { + title = tag.name; + break; + } + } + ctx.state.data = { + title: `${title} - CBNData消费站`, + link: `${rootUrl}/information${category ? `?tag_id=${category}` : ''}`, + item: items, + }; +}; diff --git a/lib/routes/dykszx/news.js b/lib/routes/dykszx/news.js new file mode 100644 index 0000000000..604a24050f --- /dev/null +++ b/lib/routes/dykszx/news.js @@ -0,0 +1,57 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const timezone = require('@/utils/timezone'); +const host = 'https://www.dykszx.com'; + +const getContent = (href, caches) => { + const newsPage = `${host}${href}`; + return caches.tryGet(newsPage, async () => { + const response = await got.get(newsPage); + const data = response.data; + const $ = cheerio.load(data); + const newsTime = $('body > div:nth-child(3) > div.page.w > div.shuxing.w') + .text() + .trim() + .match(/时间:(.*?)点击/g)[0]; + // 移除二维码 + $('.sjlook').remove(); + const content = $('#show-body').html(); + return { newsTime, content, newsPage }; + }); +}; + +const newsTypeObj = { + all: { selector: '#nrs > li > b', name: '新闻中心' }, + gwy: { selector: 'body > div:nth-child(3) > div:nth-child(8) > ul > li', name: '公务员考试' }, + sydw: { selector: 'body > div:nth-child(3) > div:nth-child(9) > ul > li', name: '事业单位考试' }, + zyzc: { selector: 'body > div:nth-child(3) > div:nth-child(10) > ul > li', name: '执(职)业资格、职称考试' }, + other: { selector: 'body > div:nth-child(3) > div:nth-child(11) > ul > li', name: '其他考试' }, +}; + +module.exports = async (ctx) => { + const newsType = ctx.params.type || 'all'; + const response = await got.get(host); + const data = response.data; + const $ = cheerio.load(data); + const newsList = $(newsTypeObj[newsType].selector).toArray(); + + const newsDetail = await Promise.all( + newsList.map(async (item) => { + const href = item.children[0].attribs.href; + const newsContent = await getContent(href, ctx.cache); + return { + title: item.children[0].children[0].data, + description: newsContent.content, + link: newsContent.newsPage, + pubDate: timezone(parseDate(newsContent.newsTime, '时间:YYYY-MM-DD HH:mm:ss'), +8), + }; + }) + ); + ctx.state.data = { + title: `德阳人事考试网 - ${newsTypeObj[newsType].name}`, + link: host, + description: '德阳人事考试网 考试新闻发布', + item: newsDetail, + }; +}; diff --git a/lib/routes/erbingapp/news.js b/lib/routes/erbingapp/news.js index b09d19920c..411474b34e 100644 --- a/lib/routes/erbingapp/news.js +++ b/lib/routes/erbingapp/news.js @@ -1,42 +1,51 @@ const got = require('@/utils/got'); +const timezone = require('@/utils/timezone'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const response = await got({ method: 'get', url: `https://api.diershoubing.com:5001/feed/tag/?pn=0&rn=20&tag_type=0&src=ios`, - resolveBodyOnly: true, - responseType: 'json', }); - const data = response.feeds; + const data = JSON.parse(response.body).feeds; + const items = data.map((item) => { + let description = `

${item.content}

`; + const acontent = item.acontent.toString(); + const ProcessDesc = (link, type) => { + if (type) { + description += `

More

`; + } else { + for (const item of link) { + description += `

`; + } + } + }; + + if (item.video_img !== null) { + ProcessDesc([item.video_img]); + } else if (acontent.indexOf('104129') !== -1) { + ProcessDesc([item.article.humb.split('?')[0]]); + } else if (acontent.indexOf('.html') !== -1) { + ProcessDesc([acontent], 'html'); + } else if (acontent.indexOf('"imgs') !== -1) { + const imgs = JSON.parse(acontent).imgs.split(','); + ProcessDesc(imgs); + } else { + const imgs = acontent.split(','); + ProcessDesc(imgs); + } + return { + title: item.title, + link: item.share.url, + description, + pubDate: timezone(parseDate(item.create_time), +8), + }; + }); ctx.state.data = { title: `二柄APP`, - link: `https://www.diershoubing.com/`, + link: `https://www.diershoubing.com`, description: `二柄APP新闻`, - item: data.map((item) => { - let description = item.content; - if (item.video_img !== null) { - description += `
`; - } else if (item.acontent.indexOf('104129') !== -1) { - description += `
`; - } else if (item.acontent.indexOf('.html') !== -1) { - description += `
More`; - } else if (item.acontent.indexOf('"imgs') !== -1) { - const imgs = item.acontent.split(','); - for (let i = 1; i < imgs.length; i++) { - description += `
`; - } - } else { - const imgs = item.acontent.split(','); - for (let i = 0; i < imgs.length; i++) { - description += `
`; - } - } - return { - description, - link: item.share.url, - title: item.title, - }; - }), + item: items, }; }; diff --git a/lib/routes/ff14/ff14_zh.js b/lib/routes/ff14/ff14_zh.js index 0a3dd45a4f..b638f01874 100644 --- a/lib/routes/ff14/ff14_zh.js +++ b/lib/routes/ff14/ff14_zh.js @@ -1,5 +1,5 @@ const got = require('@/utils/got'); - +const timezone = require('@/utils/timezone'); module.exports = async (ctx) => { const referer = 'http://ff.sdo.com/web8/index.html'; const type = ctx.params.type; @@ -29,10 +29,8 @@ module.exports = async (ctx) => { item: data.map(({ Title, Summary, Author, PublishDate, HomeImagePath }) => ({ title: Title, link: Author, - description: ` -
- ${Summary}
- ${PublishDate}`, + description: `
${Summary}`, + pubDate: timezone(new Date(PublishDate), +8), })), }; }; diff --git a/lib/routes/fzdm/manhua.js b/lib/routes/fzdm/manhua.js index b28fa5ad5d..7368cdab1a 100644 --- a/lib/routes/fzdm/manhua.js +++ b/lib/routes/fzdm/manhua.js @@ -1,27 +1,22 @@ const got = require('@/utils/got'); -const host = 'https://manhua.fzdm.com'; +const domain = 'manhua.fffdm.com'; +const host = `https://${domain}`; +const picHost = 'https://p5.fzacg.com'; const cheerio = require('cheerio'); const get_pic = (id, chapert, caches) => { - const picUrlPattern = RegExp(/var (mhurl1|mhurl)="(.*?)";/); + const picUrlPattern = RegExp(/var mhurl = "(.*?)";/); return caches.tryGet(`${host}/${id}/${chapert}/`, async () => { let is_last_page = false; let index = 0; let pic_content = ''; while (!is_last_page) { // eslint-disable-next-line no-await-in-loop - const response = await got.get(`${host}/${id}/${chapert}/index_${index}.html`, { - headers: { - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36', - Host: 'manhua.fzdm.com', - 'Accept-Encoding': 'gzip, deflate, br', - Connection: 'keep-alive', - }, - }); + const response = await got.get(`${host}/${id}/${chapert}/index_${index}.html`); const data = response.data; if (response.data !== undefined) { const picurl = data.match(picUrlPattern); - pic_content += `
`; + pic_content += `
`; if (data.match('最后一页了') !== null) { is_last_page = true; } @@ -38,7 +33,7 @@ const get_pic = (id, chapert, caches) => { module.exports = async (ctx) => { const id = ctx.params.id; - const nums = ctx.params.nums || 1; + const count = ctx.query.limit || 99999; const comicPage = host + `/${id}/`; const response = await got({ method: 'get', @@ -46,15 +41,15 @@ module.exports = async (ctx) => { }); const data = response.data; const $ = cheerio.load(data); - const list = $('div#content > li > a'); + const list = $('div#content > li > a').toArray(); const comicTitle = $('div#content > img').attr('alt').replace(/漫画/, ''); const chapter_detail = await Promise.all( - list.splice(0, nums).map(async (item) => { + list.splice(0, count).map(async (item) => { const pic_content = await get_pic(id, $(item).attr('href').replace('/', ''), ctx.cache); return { title: $(item).text().trim(), description: pic_content, - link: item.link, + link: `${comicPage}${item.attribs.href}`, }; }) ); @@ -62,10 +57,6 @@ module.exports = async (ctx) => { title: '风之动漫 - ' + comicTitle, link: comicPage, description: '风之动漫', - item: chapter_detail.map((item) => ({ - title: item.title, - description: item.description, - link: item.link, - })), + item: chapter_detail, }; }; diff --git a/lib/routes/gamer/gnn_index.js b/lib/routes/gamer/gnn_index.js index f77f843af7..0d1e48be9b 100644 --- a/lib/routes/gamer/gnn_index.js +++ b/lib/routes/gamer/gnn_index.js @@ -1,5 +1,7 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const timezone = require('@/utils/timezone'); module.exports = async (ctx) => { const category = ctx.params.category; @@ -47,37 +49,25 @@ module.exports = async (ctx) => { const list = $('div.BH-lbox.GN-lbox2') .children() - .not('.GN-lbox2A,.GN-lbox2G') + .not('p,a,img,span') .map((index, item) => { item = $(item); - const position = item.attr('class') === 'GN-lbox2F' ? 0 : 1; - const ElementA = item.find('a').eq(position); - const tagTable = { - 'IMG-Gmuti': 'General', - 'IMG-GA19': 'PC', - 'IMG-GB3': 'NS', - 'IMG-GB4': 'PS5', - 'IMG-GB1': 'PS4', - 'IMG-GB2': 'xone', - 'IMG-GB5': 'Xbox', - 'IMG-GA14': 'ARC', - 'IMG-GAC': 'AC', - 'IMG-GA13': 'ETC', - 'IMG-GA1': 'OLG', - 'IMG-Gmobi': 'MOBI', - 'IMG-GA20': 'WEB', - 'IMG-GA25': 'Google', - 'IMG-GA24': 'Apple', - 'IMG-GA28': 'Facebook', - 'IMG-GA17': 'Other', - 'IMG-GA23': 'Other', - 'IMG-Gother': 'Other', - }; - const tagValue = tagTable[item.find('img').eq(position).attr('class')]; - const tag = tagValue ? tagValue : 'Unclassified'; + let aLabelNode; + let tag; + // a label with div + if (item.children().length !== 0) { + aLabelNode = item.find('a').eq(1); + tag = item.find('div.platform-tag_list').text(); + } + // a label without div + else { + aLabelNode = item.next(); + tag = item.text(); + } + return { - title: '[' + tag + '] ' + ElementA.text(), - link: ElementA.attr('href').replace('//', 'https://'), + title: '[' + tag + '] ' + aLabelNode.text(), + link: aLabelNode.attr('href').replace('//', 'https://'), }; }) .get(); @@ -88,21 +78,44 @@ module.exports = async (ctx) => { const response = await got.get(item.link); let component = ''; const urlReg = /window.location.replace\('.*'/g; + + let pubInfo; + let dateStr; if (response.body.search(urlReg) < 0) { const $ = cheerio.load(response.data); - item.author = $('span.GN-lbox3C').text().split(')')[0].split(' 報導')[0].split(' 提供')[0].split(' 同意授權轉載')[0].replace('(', ''); + if ($('span.GN-lbox3C').length > 0) { + // official publish 1 + pubInfo = $('span.GN-lbox3C').text().split(')'); + item.author = pubInfo[0].replace('(', '').replace(' 報導', ''); + dateStr = pubInfo[1].trim(); + } else { + // official publish 2 + pubInfo = $('span.GN-lbox3CA').text().split(')'); + item.author = pubInfo[0].replace('(', '').replace(' 報導', ''); + dateStr = pubInfo[1].replace('原文出處', '').trim(); + } component = $('div.GN-lbox3B').html(); } else { + // url redirect const newUrl = response.body.match(urlReg)[0].split('(')[1].replace(/'/g, ''); const _response = await got.get(newUrl); const _$ = cheerio.load(_response.data); - item.author = _$('span.ST1').text().split('│', 2)[0].split('作者:')[1]; - component = _$('div.MSG-list8C').html(); - if (!component) { - item.author = _$('a.caption-text.primary').text(); + + if (_$('div.MSG-list8C').length > 0) { + // personal publish 1 + pubInfo = _$('span.ST1').text().split('│'); + item.author = pubInfo[0].replace('作者:', ''); + dateStr = pubInfo[_$('span.ST1').find('a').length > 0 ? 2 : 1]; + component = _$('div.MSG-list8C').html(); + } else { + // personal publish 2 + pubInfo = _$('div.article-intro').text().replace(/\n/g, '').split('|'); + item.author = pubInfo[0]; + dateStr = pubInfo[1]; component = _$('div.text-paragraph').html(); } } + item.pubDate = timezone(parseDate(dateStr, 'YYYY-MM-DD HH:mm:ss'), +8); component = component.replace(/\b(data-src)\b/g, 'src'); return component; }); diff --git a/lib/routes/gitlab/explore.js b/lib/routes/gitlab/explore.js index 6feb623481..f77939b756 100644 --- a/lib/routes/gitlab/explore.js +++ b/lib/routes/gitlab/explore.js @@ -2,7 +2,9 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); module.exports = async (ctx) => { - const type = ctx.params.type === 'all' ? '' : ctx.params.type; + let { type, host } = ctx.params; + type = type === 'all' ? '' : type; + host = host ? host : 'gitlab.com'; const typename = { trending: 'Trending', starred: 'Most stars', @@ -11,14 +13,14 @@ module.exports = async (ctx) => { const res = await got({ method: 'get', - url: `https://gitlab.com/explore/projects/${type}`, + url: `https://${host}/explore/projects/${type}`, }); const $ = cheerio.load(res.data); const list = $('ul.projects-list').find('li'); ctx.state.data = { title: `${typename[ctx.params.type]} - Explore - Gitlab`, - link: `https://gitlab.com/explore/projects/${type}`, + link: `https://${host}/explore/projects/${type}`, item: list && list @@ -28,7 +30,7 @@ module.exports = async (ctx) => { title: item.find('.project-full-name').text(), author: item.find('.namespace-name').text().slice(0, -1).split('\n').join('').trim(), description: item.find('.description').text(), - link: `https://gitlab.com${item.find('a.text-plain').attr('href')}`, + link: `https://${host}${item.find('a.text-plain').attr('href')}`, }; }) .get(), diff --git a/lib/routes/gitlab/release.js b/lib/routes/gitlab/release.js new file mode 100644 index 0000000000..ee734df265 --- /dev/null +++ b/lib/routes/gitlab/release.js @@ -0,0 +1,30 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const { namespace, project, host } = ctx.params; + + const host_ = host ? host : 'gitlab.com'; + const namespace_ = encodeURIComponent(namespace); + + const api_url = `https://${host_}/api/v4/projects/${namespace_}%2F${project}/releases`; + + const response = await got({ + method: 'get', + url: api_url, + }); + const data = response.data; + + ctx.state.data = { + title: `${project} - Releases - Gitlab`, + link: `https://${host_}/${namespace}/${project}/-/releases`, + description: `${namespace}/${project} Releases`, + item: data.map((item) => ({ + title: item.name, + author: item.author.name, + description: item.description_html, + pubDate: parseDate(item.released_at), + link: item._links.self, + })), + }; +}; diff --git a/lib/routes/gitlab/tag.js b/lib/routes/gitlab/tag.js new file mode 100644 index 0000000000..6e267be525 --- /dev/null +++ b/lib/routes/gitlab/tag.js @@ -0,0 +1,30 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const { namespace, project, host } = ctx.params; + + const host_ = host ? host : 'gitlab.com'; + const namespace_ = encodeURIComponent(namespace); + + const api_url = `https://${host_}/api/v4/projects/${namespace_}%2F${project}/repository/tags`; + + const response = await got({ + method: 'get', + url: api_url, + }); + const data = response.data; + + ctx.state.data = { + title: `${project} - Tags - Gitlab`, + link: `https://${host_}/${namespace}/${project}/-/tags`, + description: `${namespace}/${project} Tags`, + item: data.map((item) => ({ + title: item.name, + author: item.commit.author_name, + description: item.message, + pubDate: parseDate(item.commit.created_at), + link: item.commit.web_url, + })), + }; +}; diff --git a/lib/routes/kaopunews/all.js b/lib/routes/kaopunews/all.js deleted file mode 100644 index 8085a9f93f..0000000000 --- a/lib/routes/kaopunews/all.js +++ /dev/null @@ -1,30 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); - -module.exports = async (ctx) => { - const response = await got({ - method: 'get', - url: 'https://kaopu.news/', - }); - - const data = response.data; - - const $ = cheerio.load(data); - const list = $('a[target="_blank"]'); - ctx.state.data = { - title: '靠谱新闻', - link: 'https://kaopu.news/', - item: - list && - list - .map((index, item) => { - item = $(item); - return { - title: `${item.find('h3').text()}(${item.attr('class').substring(8)})`, - description: item.find('h3').next().next().text(), - link: item.attr('href'), - }; - }) - .get(), - }; -}; diff --git a/lib/routes/kaopunews/index.js b/lib/routes/kaopunews/index.js new file mode 100644 index 0000000000..e848e9c55d --- /dev/null +++ b/lib/routes/kaopunews/index.js @@ -0,0 +1,28 @@ +const got = require('@/utils/got'); + +module.exports = async (ctx) => { + const language = ctx.params.language || ''; + + const rootUrl = 'https://kaopu.news'; + const currentUrl = `${rootUrl}/${language === 'zh-hant' ? 'zh-hant' : 'index'}.html`; + const apiUrl = `https://kaopucdn.azureedge.net/jsondata/news_han${language === 'zh-hant' ? 't' : 's'}_0.json`; + + const response = await got({ + method: 'get', + url: apiUrl, + }); + + const items = response.data.map((item) => ({ + link: item.link, + title: item.title, + author: item.publisher, + pubDate: new Date(item.first_seen * 1000), + description: `

${item.story_summary}

`, + })); + + ctx.state.data = { + title: language === 'zh-hant' ? '靠譜新聞' : '靠谱新闻', + link: currentUrl, + item: items, + }; +}; diff --git a/lib/routes/mhgui/comic.js b/lib/routes/mhgui/comic.js new file mode 100644 index 0000000000..ae28a18591 --- /dev/null +++ b/lib/routes/mhgui/comic.js @@ -0,0 +1,53 @@ +const { resolve } = require('url'); +const cheerio = require('cheerio'); +const got = require('@/utils/got'); +const LZString = require('lz-string'); + +const getChapters = ($) => + $('.chapter-list > ul') + .toArray() + .reverse() + .reduce((acc, curr) => acc.concat($(curr).children('li').toArray()), []) + .map((ele) => { + const a = $(ele).children('a'); + return { + link: resolve('https://www.mhgui.com/', a.attr('href')), + title: a.attr('title'), + num: a.find('i').text(), + }; + }); + +module.exports = async (ctx) => { + const { id } = ctx.params; + + const { data } = await got.get(`https://www.mhgui.com/comic/${id}/`); + const $ = cheerio.load(data); + + if ($('#__VIEWSTATE').length > 0) { + const n = LZString.decompressFromBase64($('#__VIEWSTATE').val()); + if (n) { + $('#erroraudit_show').replaceWith(n); + $('#__VIEWSTATE').remove(); + } + } + + const bookTitle = $('.book-title > h1').text(); + const bookIntro = $('#intro-all').text(); + const coverImgSrc = $('.book-cover img').attr('src'); + const chapters = getChapters($); + + const genResult = (chapter) => ({ + link: chapter.link, + title: chapter.title, + description: ` +

${chapter.num}

+ + `.trim(), + }); + ctx.state.data = { + title: `看漫画 - ${bookTitle}`, + link: `https://www.mhgui.com/comic/${id}/`, + description: bookIntro, + item: chapters.map(genResult), + }; +}; diff --git a/lib/routes/netease/dy.js b/lib/routes/netease/dy.js index 51364c675a..da60a8472a 100644 --- a/lib/routes/netease/dy.js +++ b/lib/routes/netease/dy.js @@ -7,7 +7,7 @@ module.exports = async (ctx) => { const { id } = ctx.params; const response = await got.get(`http://dy.163.com/v2/article/list.do?pageNo=1&wemediaId=${id}&size=10`); - + const charset = response.headers['content-type'].split('=')[1]; const list = response.data.data.list; let author, link; @@ -26,7 +26,7 @@ module.exports = async (ctx) => { responseType: 'buffer', }) ).data, - 'gbk' + charset ) ); const $ = cheerio.load(html, { decodeEntities: false }); diff --git a/lib/routes/netease/dy2.js b/lib/routes/netease/dy2.js index c9344bbf59..9821cdb97d 100644 --- a/lib/routes/netease/dy2.js +++ b/lib/routes/netease/dy2.js @@ -8,7 +8,8 @@ module.exports = async (ctx) => { const response = await got.get(url, { responseType: 'buffer' }); - const data = iconv.decode(response.data, 'gbk'); + const charset = response.headers['content-type'].split('=')[1]; + const data = iconv.decode(response.data, charset); const $ = cheerio.load(data, { decodeEntities: false }); const list = $('.media_articles ul li') @@ -39,7 +40,7 @@ module.exports = async (ctx) => { responseType: 'buffer', }) ).data, - 'gbk' + charset ) ); content = cheerio.load(itemData, { decodeEntities: false }); diff --git a/lib/routes/nytimes/daily_briefing_chinese.js b/lib/routes/nytimes/daily_briefing_chinese.js index 663877dd0a..5e241699b8 100644 --- a/lib/routes/nytimes/daily_briefing_chinese.js +++ b/lib/routes/nytimes/daily_briefing_chinese.js @@ -28,15 +28,26 @@ module.exports = async (ctx) => { async (item) => await ctx.cache.tryGet(item.link, async () => { const response = await got.get(item.link); - const $ = cheerio.load(response.data); + const data = response.data; + const arr = data.match(/"url":"https:\\u002F\\u002Fstatic(\S*)"articleLarge"/g); + const imageLink = arr.map((e) => JSON.parse(`{${e}}`).url); + + const $ = cheerio.load(data); $('.css-pncxxs.etfikam0').remove(); - $('.css-1xdhyk6.erfvjey0').each((_, item) => { - item = $(item); - const link = item.find('img').attr('src'); - item.replaceWith(``); + // remove 'Credit...' + $('.css-1ly73wi.e1tej78p0').remove(); + $('.css-1xdhyk6.erfvjey0').each((i, e) => $(e).replaceWith(``)); + + $('.css-1l44abu.ewdxa0s0').each((i, e) => { + const figureNote = $(e) + .children() + .map((i, e) => $(e).text()) + .get(); + $(e).replaceWith(`

${figureNote.join(' ')}

`); }); + const date = $('time').attr('datetime'); + item.description = $('.meteredContent.css-1r7ky0e').html(); - const date = $('.css-x7rtpa.e16638kd0').attr('datetime'); item.pubDate = parseDate(date); return item; }) diff --git a/lib/routes/pjsk/news.js b/lib/routes/pjsk/news.js new file mode 100644 index 0000000000..8861ced20a --- /dev/null +++ b/lib/routes/pjsk/news.js @@ -0,0 +1,49 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); +module.exports = async (ctx) => { + // 从仓库 Sekai-World/sekai-master-db-diff 获取最新公告 + const response = await got.get(`https://cdn.jsdelivr.net/gh/Sekai-World/sekai-master-db-diff@master/userInformations.json`); + const posts = response.data || []; + const list = await Promise.all( + posts.map(async (post) => { + let link = ''; + let description = ''; + const guid = post.displayOrder.toString() + post.id.toString(); // 双ID + if (post.path.startsWith('information/')) { + // information 公告 + const path = post.path.replace(/information\/index.html\?id=/, ''); + link = `https://production-web.sekai.colorfulpalette.org/${post.path}`; + try { + description = await ctx.cache.tryGet(guid, async () => { + const result = await got.get(`https://production-web.sekai.colorfulpalette.org/html/${path}.html`); + const $ = cheerio.load(result.data); + return $('body').html(); + }); + } catch { + description = link; + } + } else { + // 外链 + link = post.path; + description = post.title; + } + + const item = { + title: post.title, + link: link, + pubDate: timezone(new Date(post.startAt), +8), // +8时区 + description: description, + category: post.informationTag, // event,gacha,music,bug,information + guid: guid, + }; + return Promise.resolve(item); + }) + ); + ctx.state.data = { + title: 'Project Sekai - News', + link: 'https://pjsekai.sega.jp/', + description: 'プロジェクトセカイ カラフルステージ! feat.初音ミク', + item: list, + }; +}; diff --git a/lib/routes/potplayer/update.js b/lib/routes/potplayer/update.js new file mode 100644 index 0000000000..a47fdffc1d --- /dev/null +++ b/lib/routes/potplayer/update.js @@ -0,0 +1,42 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const language = ctx.params.language || 'en'; + const bar = '-'.repeat(language.length > 2 ? 74 : 58); + + const rootUrl = 'https://potplayer.daum.net'; + const currentUrl = `${rootUrl}/?lang=${language}`; + + const link = await ctx.cache.tryGet(currentUrl, async () => { + const response = await got({ + method: 'get', + url: currentUrl, + }); + return response.data.match(//)[1]; + }); + + const response = await got({ + method: 'get', + url: link, + }); + + const list = response.data.split(`\r\n\r\n${bar}\r\n`); + + const items = list.slice(1, 10).map((item) => { + const pubDate = parseDate(item.substr(1, 6), 'YYMMDD'); + + return { + pubDate, + link: currentUrl, + title: item.substr(1, 6), + description: `

`, + }; + }); + + ctx.state.data = { + title: list[0].split('\r\n\r\n').pop(), + link: currentUrl, + item: items, + }; +}; diff --git a/lib/routes/zcool/discovery.js b/lib/routes/rmlt/idea.js similarity index 53% rename from lib/routes/zcool/discovery.js rename to lib/routes/rmlt/idea.js index f0f05fb559..b8747bdac4 100644 --- a/lib/routes/zcool/discovery.js +++ b/lib/routes/rmlt/idea.js @@ -1,22 +1,29 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { - const query = ctx.params.query || '0!0!0!0!0!!!!2!-1!1'; + const category = ctx.params.category || ''; + + const rootUrl = 'http://www.rmlt.com.cn'; + const currentUrl = `${rootUrl}/idea/${category}`; - const rootUrl = `https://www.zcool.com.cn/discover/${query}`; const response = await got({ method: 'get', - url: rootUrl, + url: currentUrl, }); + const $ = cheerio.load(response.data); - const list = $('.work-list-box > .card-box') + const list = $(category ? '.txt-list' : '.hot-news') + .find('a') + .slice(0, 15) .map((_, item) => { item = $(item); + return { - link: item.find('.card-info-title a[title]').attr('href'), - author: item.find('.user-avatar').find('a').attr('title'), + link: item.attr('href'), }; }) .get(); @@ -31,9 +38,9 @@ module.exports = async (ctx) => { }); const content = cheerio.load(detailResponse.data); - item.title = content('h2').text(); - item.pubDate = new Date(content('.title-time').attr('title').split('创建时间:')[1]).toUTCString(); - item.description = item.link.indexOf('article') < 0 ? content('.work-content-wrap').html() : content('.article-content-wraper').html(); + item.title = content('.article-title').text(); + item.description = content('.article-content').html(); + item.pubDate = timezone(parseDate(content('.date').text(), 'YYYY-MM-DD HH:ss'), +8); return item; }) @@ -41,8 +48,8 @@ module.exports = async (ctx) => { ); ctx.state.data = { - title: `站酷 - ${query}`, - link: rootUrl, + title: $('title').text(), + link: currentUrl, item: items, }; }; diff --git a/lib/routes/sspai/author.js b/lib/routes/sspai/author.js index a5f17f417b..327493520a 100644 --- a/lib/routes/sspai/author.js +++ b/lib/routes/sspai/author.js @@ -48,7 +48,7 @@ module.exports = async (ctx) => { title: item.title.trim(), description: description, link: link, - pubDate: new Date(item.released_at * 1000).toUTCString(), + pubDate: new Date(item.released_at * 1000), author: item.author.nickname, }; }) diff --git a/lib/routes/sspai/column.js b/lib/routes/sspai/column.js index 82766c600e..2e5d803ec4 100644 --- a/lib/routes/sspai/column.js +++ b/lib/routes/sspai/column.js @@ -50,7 +50,7 @@ module.exports = async (ctx) => { link: itemUrl, author: author, description: description, - pubDate: new Date(date * 1000).toUTCString(), + pubDate: new Date(date * 1000), }; ctx.cache.set(itemUrl, JSON.stringify(single)); return Promise.resolve(single); diff --git a/lib/routes/sspai/matrix.js b/lib/routes/sspai/matrix.js index 1102fbf5c8..65241f90d1 100644 --- a/lib/routes/sspai/matrix.js +++ b/lib/routes/sspai/matrix.js @@ -29,7 +29,7 @@ module.exports = async (ctx) => { title: item.title.trim(), description: description, link: link, - pubDate: new Date(item.released_at * 1000).toUTCString(), + pubDate: new Date(item.released_at * 1000), author: item.author.nickname, }; }) diff --git a/lib/routes/sspai/shortcutsGallery.js b/lib/routes/sspai/shortcutsGallery.js index c86f04d804..668d940d12 100644 --- a/lib/routes/sspai/shortcutsGallery.js +++ b/lib/routes/sspai/shortcutsGallery.js @@ -12,7 +12,7 @@ module.exports = async (ctx) => { items.push({ title: shortcut.name, description: `作者:${shortcut.author_id}
${decodeURIComponent((shortcut.description || '').replace(/\+/g, '%20'))}`, - pubDate: new Date(shortcut.utime * 1000).toUTCString(), + pubDate: new Date(shortcut.utime * 1000), guid: shortcut.id, link: shortcut.url, }); diff --git a/lib/routes/sspai/tag.js b/lib/routes/sspai/tag.js index 6d337b6b68..906252639b 100644 --- a/lib/routes/sspai/tag.js +++ b/lib/routes/sspai/tag.js @@ -3,7 +3,7 @@ const cheerio = require('cheerio'); module.exports = async (ctx) => { const keyword = ctx.params.keyword; - const keyword_encode = encodeURIComponent(keyword); + const keyword_encode = encodeURIComponent(decodeURIComponent(keyword)); const api_url = `https://sspai.com/api/v1/articles?offset=0&limit=50&has_tag=1&tag=${keyword_encode}&include_total=false`; const host = `https://beta.sspai.com/tag/${keyword_encode}`; const resp = await got({ @@ -25,14 +25,14 @@ module.exports = async (ctx) => { } else { const response = await got({ method: 'get', url: link, headers: { Referer: host } }); const $ = cheerio.load(response.data); - description = $('div.content.wangEditor-txt.clock').html(); + description = $('div.content.wangEditor-txt').html(); ctx.cache.set(key, description); } return { title: item.title.trim(), description: description, link: link, - pubDate: new Date(item.released_at * 1000).toUTCString(), + pubDate: new Date(item.released_at * 1000), author: item.author.nickname, }; }) diff --git a/lib/routes/sspai/topic.js b/lib/routes/sspai/topic.js index e9ccd86f16..d1599cb06b 100644 --- a/lib/routes/sspai/topic.js +++ b/lib/routes/sspai/topic.js @@ -37,7 +37,7 @@ module.exports = async (ctx) => { link: itemUrl, author: author, description: description, - pubDate: new Date(date * 1000).toUTCString(), + pubDate: new Date(date * 1000), }; ctx.cache.set(itemUrl, JSON.stringify(single)); return Promise.resolve(single); diff --git a/lib/routes/sspai/topics.js b/lib/routes/sspai/topics.js index bc9d2a138a..440e4c2965 100644 --- a/lib/routes/sspai/topics.js +++ b/lib/routes/sspai/topics.js @@ -26,7 +26,7 @@ module.exports = async (ctx) => { title: item.title.trim(), description: description, link: link, - pubDate: new Date(item.released_at * 1000).toUTCString(), + pubDate: new Date(item.released_at * 1000), author: item.author.nickname, }; }) diff --git a/lib/routes/szse/projectdynamic.js b/lib/routes/szse/projectdynamic.js new file mode 100644 index 0000000000..9c734f579d --- /dev/null +++ b/lib/routes/szse/projectdynamic.js @@ -0,0 +1,104 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const typeMap = { + 1: 'IPO', + 2: '再融资', + 3: '重大资产重组', + }; + + const stageMap = { + 10: '受理', + 20: '问询', + 30: '上市委会议', + 35: '提交注册', + 40: '注册结果', + 50: '中止', + 60: '终止', + }; + + const statusMap = { + 20: '新受理', + 30: '已问询', + 45: '通过', + 44: '未通过', + 46: '暂缓审议', + 56: '复审通过', + 54: '复审不通过', + 60: '提交注册', + 70: '注册生效', + 74: '不予注册', + 78: '补充审核', + 76: '终止注册', + 80: '中止', + 90: '审核不通过', + 95: '撤回', + }; + + const type = ctx.params.type || '1'; + const stage = ctx.params.stage || '0'; + const status = ctx.params.status || '0'; + + const rootUrl = 'http://listing.szse.cn'; + const apiUrl = `${rootUrl}/api/ras/projectrends/query?bizType=${type}${stage === '0' ? '' : `&stage=${stage}`}${status === '0' ? '' : `&status=${status}`}&pageIndex=0&pageSize=20`; + + const response = await got({ + method: 'get', + url: apiUrl, + }); + + const list = response.data.data.map((item) => ({ + title: item.prjid, + link: `${rootUrl}/api/ras/projectrends/details?id=${item.prjid}`, + })); + + const items = await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + + const data = detailResponse.data.data; + const current = JSON.parse(data.pjdot)['-1']; + + item.link = `${rootUrl}/projectdynamic/ipo/detail/index.html?id=${item.title}`; + item.title = `[${data.prjst}] ${data.cmpnm} (${data.cmpsnm})- ${data.csrcind}`; + + item.description = + `

${data.cmpnm}

${current.startTime} ${current.name}

项目基本信息

` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `` + + `
公司全称${data.cmpnm}公司简称${data.cmpsnm}
受理日期${data.acptdt}更新日期${data.updtdt}
审核状态${data.prjst}预计融资金额(亿元)${data.maramt}
保荐机构${data.sprinst}保荐代表人${data.sprrep}
会计师事务所${data.acctfm}签字会计师${data.acctsgnt}
律师事务所${data.lawfm}签字律师${data.lglsgnt}
评估机构${data.evalinst}签字评估师${data.evalsgnt}
最近一期审计基准日${data.lastestAuditEndDate}
`; + + item.pubDate = parseDate(current.startTime, 'YYYY-MM-DD HH:mm:ss'); + + return item; + }) + ) + ); + + ctx.state.data = { + title: `${typeMap[type]}项目动态${status !== '0' ? ` (${statusMap[status]}) ` : stage !== '0' ? ` (${stageMap[stage]}) ` : ''} - 创业板发行上市审核信息公开网站 - 深圳证券交易所`, + link: `${rootUrl}/projectdynamic/${type}/index.html`, + item: items, + }; +}; diff --git a/lib/routes/tanchinese/index.js b/lib/routes/tanchinese/index.js new file mode 100644 index 0000000000..4ccda29075 --- /dev/null +++ b/lib/routes/tanchinese/index.js @@ -0,0 +1,54 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const category = ctx.params.category || ''; + + const rootUrl = 'http://www.tanchinese.com'; + const currentUrl = `${rootUrl}${category ? `/archives/${category}` : ''}`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const list = $('.archive-grid-caption .h2') + .map((_, item) => { + item = $(item); + + return { + title: item.text(), + link: item.attr('href'), + }; + }) + .get(); + + const items = await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + const content = cheerio.load(detailResponse.data); + + item.description = content('.article-content').html(); + item.pubDate = timezone(parseDate(content('#page-content .row .col-xs-12 small').eq(0).text(), 'MMM DD, YYYY'), +8); + + return item; + }) + ) + ); + + ctx.state.data = { + title: $('title').text(), + link: currentUrl, + item: items, + description: $('meta[name="description"]').attr('content'), + }; +}; diff --git a/lib/routes/tieba/user.js b/lib/routes/tieba/user.js index bbe5c54512..1913c2e15e 100644 --- a/lib/routes/tieba/user.js +++ b/lib/routes/tieba/user.js @@ -1,31 +1,36 @@ const got = require('@/utils/got'); +const cheerio = require('cheerio'); module.exports = async (ctx) => { const uid = ctx.params.uid; - - const rootUrl = 'https://tieba.baidu.com'; - const userUrl = `${rootUrl}/home/get/getthread?un=${uid}&pn=1&ie=utf8`; const response = await got({ method: 'get', - url: userUrl, + url: `https://tieba.baidu.com/home/main?un=${uid}`, }); + const data = response.data; + + const $ = cheerio.load(data); + const name = $('span.userinfo_username').text(); + const list = $('div.n_right.clearfix'); + let imgurl; + ctx.state.data = { - title: `${uid}的贴子 - 百度贴吧`, - link: `${rootUrl}/home/main?un=${uid}`, - item: response.data.data.thread_list.map((item) => { - let media = ''; - if (item.media) { - for (const m of item.media) { - media += ``; - } - } - return { - title: item.title, - description: `

${item.content}

${media}`, - pubDate: new Date(item.create_time * 1000).toUTCString(), - link: `https://tieba.baidu.com/p/${item.thread_id}?pid=${item.post_id}&cid=#${item.post_id}`, - }; - }), + title: `${name} 的贴吧`, + link: `https://tieba.baidu.com/home/main?un=${uid}`, + item: + list && + list + .map((index, item) => { + item = $(item).find('.n_contain'); + imgurl = item.find('ul.n_media.clearfix img').attr('original'); + return { + title: item.find('div.thread_name a').attr('title'), + pubDate: Date.parse(item.parent().find('div .n_post_time').text()), + description: `${item.find('div.n_txt').text()}
`, + link: item.find('div.thread_name a').attr('href'), + }; + }) + .get(), }; }; diff --git a/lib/routes/twmanhuagui/comic.js b/lib/routes/twmanhuagui/comic.js new file mode 100644 index 0000000000..090645acfe --- /dev/null +++ b/lib/routes/twmanhuagui/comic.js @@ -0,0 +1,53 @@ +const { resolve } = require('url'); +const cheerio = require('cheerio'); +const got = require('@/utils/got'); +const LZString = require('lz-string'); + +const getChapters = ($) => + $('.chapter-list > ul') + .toArray() + .reverse() + .reduce((acc, curr) => acc.concat($(curr).children('li').toArray()), []) + .map((ele) => { + const a = $(ele).children('a'); + return { + link: resolve('https://tw.manhuagui.com/', a.attr('href')), + title: a.attr('title'), + num: a.find('i').text(), + }; + }); + +module.exports = async (ctx) => { + const { id } = ctx.params; + + const { data } = await got.get(`https://tw.manhuagui.com/comic/${id}/`); + const $ = cheerio.load(data); + + if ($('#__VIEWSTATE').length > 0) { + const n = LZString.decompressFromBase64($('#__VIEWSTATE').val()); + if (n) { + $('#erroraudit_show').replaceWith(n); + $('#__VIEWSTATE').remove(); + } + } + + const bookTitle = $('.book-title > h1').text(); + const bookIntro = $('#intro-all').text(); + const coverImgSrc = $('.book-cover img').attr('src'); + const chapters = getChapters($); + + const genResult = (chapter) => ({ + link: chapter.link, + title: chapter.title, + description: ` +

${chapter.num}

+ + `.trim(), + }); + ctx.state.data = { + title: `看漫画 - ${bookTitle}`, + link: `https://tw.manhuagui.com/comic/${id}/`, + description: bookIntro, + item: chapters.map(genResult), + }; +}; diff --git a/lib/routes/universities/harvard/health/blog.js b/lib/routes/universities/harvard/health/blog.js new file mode 100644 index 0000000000..6f4dd59abc --- /dev/null +++ b/lib/routes/universities/harvard/health/blog.js @@ -0,0 +1,52 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +module.exports = async (ctx) => { + const rootUrl = 'https://www.health.harvard.edu'; + const currentUrl = `${rootUrl}/blog`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const list = $('.text-2xl') + .slice(0, 10) + .map((_, item) => { + item = $(item).parent(); + + return { + title: item.text(), + link: item.attr('href'), + }; + }) + .get(); + + const items = await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + const content = cheerio.load(detailResponse.data); + + const date = item.link.substr(item.link.length - 12, 8); + + item.description = content('.content-repository-content').html(); + item.pubDate = Date.parse(`${date.substr(0, 4)}-${date.substr(4, 2)}-${date.substr(6, 2)}`); + + return item; + }) + ) + ); + + ctx.state.data = { + title: 'Harvard Health Blog', + link: currentUrl, + item: items, + }; +}; diff --git a/lib/routes/universities/scut/seie/news_center.js b/lib/routes/universities/scut/seie/news_center.js new file mode 100644 index 0000000000..5ed2c01f18 --- /dev/null +++ b/lib/routes/universities/scut/seie/news_center.js @@ -0,0 +1,58 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const rootUrl = 'https://www2.scut.edu.cn'; + const url = `${rootUrl}/ee/16285/list.htm`; + const response = await got.get(url); + const $ = cheerio.load(response.data); + + const list = $('.news_ul li'); + const articleList = list + .map((_, item) => { + item = $(item); + const titleElement = item.find('.news_title a'); + return { + title: titleElement.attr('title'), + link: titleElement.attr('href'), + pubDate: parseDate(item.find('.news_meta').text(), 'YYYY-MM-DD'), + }; + }) + .get(); + + const items = await Promise.all( + articleList.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: `${rootUrl}${item.link}`, + }); + const content = cheerio.load(detailResponse.data, { decodeEntities: false }); + + content('.wp_articlecontent *').each((_, child) => { + const childElem = content(child); + childElem.removeAttr('style'); + childElem.removeAttr('lang'); + childElem.removeAttr('original-src'); + childElem.removeAttr('sudyfile-attr'); + childElem.removeAttr('data-layer'); + if ((!childElem.text().replace('\n', '').trim().length && !childElem.has('img')) || childElem.attr('name') === '_GoBack' || childElem.is('style')) { + childElem.remove(); + } + }); + + const contentHTML = content('.wp_articlecontent').html(); + item.description = contentHTML.replace(/^(
)+|(
)+$/g, '').trim(); + return item; + }) + ) + ); + + ctx.state.data = { + title: '华南理工大学电子与信息学院 - 新闻速递', + link: url, + item: items, + }; +}; diff --git a/lib/routes/universities/xjtu/ee.js b/lib/routes/universities/xjtu/ee.js new file mode 100644 index 0000000000..7cba69ac8b --- /dev/null +++ b/lib/routes/universities/xjtu/ee.js @@ -0,0 +1,45 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const timezone = require('@/utils/timezone'); + +module.exports = async (ctx) => { + const id = ctx.params.id || '1124'; + const rootUrl = `http://ee.xjtu.edu.cn/list.jsp?urltype=tree.TreeTempUrl&wbtreeid=${id}`; + const baseUrl = 'http://ee.xjtu.edu.cn'; + + const list_response = await got.get(rootUrl); + const $ = cheerio.load(list_response.data); + + const feed_title = $('span.windowstyle67278', "div[class='list_right fr']").text().trim(); + + const list = $("div[class='list_right fr'] ul li") + .slice(0, 10) + .map((_, item) => { + item = $(item); + const a = item.find('a'); + const date = parseDate(item.find('span').text()); + return { + title: a.text(), + link: new URL(a.attr('href'), baseUrl), + pubDate: timezone(date, +8), + }; + }) + .get(); + + ctx.state.data = { + title: `西安交通大学电气学院 - ${feed_title}`, + link: baseUrl, + item: await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const res = await got.get(item.link); + const content = cheerio.load(res.data); + item.description = content('td.contentstyle67362', 'form').html(); + return item; + }) + ) + ), + }; +}; diff --git a/lib/routes/universities/xjtu/job.js b/lib/routes/universities/xjtu/job.js new file mode 100644 index 0000000000..ce2da33838 --- /dev/null +++ b/lib/routes/universities/xjtu/job.js @@ -0,0 +1,51 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const timezone = require('@/utils/timezone'); + +module.exports = async (ctx) => { + const subpath = ctx.params.subpath || 'zxtg'; + const arr = { + zxtg: '中心通告', + xdsgwy: '选调生|公务员', + gjzzsx: '国际组织实习', + xwzx: '新闻资讯', + hdyjz: '活动与讲座', + }; + const rootUrl = `https://job.xjtu.edu.cn/news.do;?ext=${arr[subpath]}`; + const baseUrl = 'https://job.xjtu.edu.cn'; + + const list_response = await got.get(rootUrl); + const $ = cheerio.load(list_response.data); + + const list = $('div.jsnr ul li') + .slice(0, 10) + .map((_, item) => { + item = $(item); + const a = item.find('a'); + return { + title: a.find('span').text(), + link: new URL(a.attr('href'), baseUrl), + }; + }) + .get(); + + ctx.state.data = { + title: `西安交通大学就业网-${arr[subpath]}`, + link: baseUrl, + item: await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const res = await got.get(item.link); + const content = cheerio.load(res.data); + item.description = content('div.jsnr').html(); + const dateStr = content('div.jsnrly span').eq(1).text(); + const date = parseDate(dateStr, 'YYYY MM DD HH mm', 'zh-cn'); + item.pubDate = timezone(date, +8); + return item; + }) + ) + ), + }; +}; diff --git a/lib/routes/xueqiu/stock_comments.js b/lib/routes/xueqiu/stock_comments.js new file mode 100644 index 0000000000..47e4550c9f --- /dev/null +++ b/lib/routes/xueqiu/stock_comments.js @@ -0,0 +1,61 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const template = require('art-template'); +const { parseDate } = require('@/utils/parse-date'); + +const description_template = ` + +
{{item.user.screen_name}}:
+
+
+{{item.text}} +
+{{if item.retweeted_status}} +
+{{item.retweeted_status.text}} +{{else}} +
+{{/if}} +
+ ----来源于:{{item.source}} +
`; + +module.exports = async (ctx) => { + const id = ctx.params.id; + const titleLength = ctx.params.titleLength || 30; + + const res = await got({ + method: 'get', + url: `https://xueqiu.com/query/v1/symbol/search/status?u=11111&count=100&comment=0&symbol=${id}&source=all&sort=time`, + }); + + // 获取stock_name + const stock_name = await ctx.cache.tryGet(`stock_name_${id}`, async () => { + const res = await got({ + method: 'get', + url: `https://xueqiu.com/S/${id}`, + }); + const $ = cheerio.load(res.data); // 使用 cheerio 加载返回的 HTML + return $('.stock-name').text().split('(')[0]; + }); + + const data = res.data.list; + ctx.state.data = { + title: `${id} ${stock_name} - 评论`, + link: `https://xueqiu.com/S/${id}`, + description: `${stock_name} - 评论`, + item: data.map((item) => { + let link = `https://xueqiu.com${item.target}`; + if (item.quote_cards) { + link = item.quote_cards[0].target_url; + } + const description = template.render(description_template, { item: item }); + return { + title: item.title !== '' ? item.title : item.text.replace(/<[^>]+>/g, '').slice(0, titleLength), + description: description, + pubDate: parseDate(item.created_at), + link, + }; + }), + }; +}; diff --git a/lib/routes/yomiuri/news.js b/lib/routes/yomiuri/news.js index e61dcabc96..18cc5ef55c 100644 --- a/lib/routes/yomiuri/news.js +++ b/lib/routes/yomiuri/news.js @@ -1,5 +1,6 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); module.exports = async (ctx) => { const category = ctx.params.category; @@ -12,30 +13,99 @@ module.exports = async (ctx) => { const data = response.data; const $ = cheerio.load(data); - let category_name = ''; + let categoryName; let list = null; if (category === 'news') { - category_name = '総合'; - list = $('ul.news-top-upper-content-topics-content-list.p-list').children('li').not('.p-member-only'); + categoryName = '新着・速報'; + const urlPrefix = 'https://www.yomiuri.co.jp/y_ajax/'; + + // get list1 + const param1 = $('input#latest_list_news_other_params').val(); + const response1 = await got({ + method: 'get', + url: urlPrefix + 'latest_list_news/' + param1 + '/?action=latest_list_news&others=' + param1, + }); + const data1 = response1.data; + const firstArticleList = cheerio.load(data1); + + // get list2 + const param2 = $('input#latest_list_news_other_params2').val(); + const response2 = await got({ + method: 'get', + url: urlPrefix + 'latest_list_news2/' + param2 + '/?action=latest_list_news2&others=' + param2, + }); + const data2 = response2.data; + const secondArticleList = cheerio.load(data2); + list = secondArticleList('article').add(firstArticleList('article')); + + list = list.map((index, item) => { + item = $(item); + // remove matome title + const matomeTitle = item.find('div.c-matome-title'); + if (matomeTitle.length !== 0) { + matomeTitle.remove(); + } + // remove member only + const lockedIcon = item.find('svg[class=icon-locked]'); + if (lockedIcon.length === 0) { + return item; + } else { + return null; + } + }); } else { - category_name = $('h1.p-header-category-current-title').text(); - list = $('div.p-category-organization,.p-category-time-series').find('li').not('.p-member-only').not('.p-ad-list-item'); + let parentSelector = 'div.p-category-organization,.p-category-time-series'; + // igoshougi channel sepcial div selector + if (category === 'igoshougi') { + parentSelector = 'div.uni-news-igoshougi-top'; + } + categoryName = $('h1.p-header-category-current-title,h1.p-header-category-content-title').text(); + // p-header-category-content-title + list = $(parentSelector).find('li').not('.p-member-only').not('.p-ad-list-item'); + list = list.map((index, item) => { + item = $(item); + // remove matome title + const matomeTitle = item.find('div.c-matome-title'); + if (matomeTitle.length !== 0) { + matomeTitle.remove(); + } + return item; + }); + } + + // format category name + if (categoryName !== '') { + categoryName = ' - ' + categoryName.trim(); } const items = await Promise.all( list .map(async (index, item) => { item = $(item); - const link = item.find('a').attr('href'); + + let link = ''; + if (categoryName === '新着・速報') { + link = item.find('h3').children('a').attr('href'); + } else { + link = item.find('a').attr('href'); + } + const description = await ctx.cache.tryGet(link, async () => { const response = await got.get(link); const $ = cheerio.load(response.data); - return $('div.p-main-contents').html(); + const mainContent = $('div.p-main-contents'); + // remove articles recomended + const recommendNode = mainContent.find('aside.ev-article-manual-related__article-inline'); + if (recommendNode.length !== 0) { + recommendNode.remove(); + } + return mainContent.html(); }); + let tag = ''; - if (category_name === '総合') { + if (categoryName === '新着・速報') { const tag_table = { - news: '総合', + news: '新着・速報', national: '社会', politics: '政治', economy: '経済', @@ -49,14 +119,17 @@ module.exports = async (ctx) => { local: '地域', editorial: '社説', medical: '医療・健康', + olympic: 'オリンピック', }; const tag_value = tag_table[link.split('/')[3]]; tag = tag_value ? tag_value : 'その他'; tag = '[' + tag + '] '; } + return { title: tag + item.find('a').text(), description, + pubDate: timezone(new Date(item.find('time').prop('datetime')), +9), link, }; }) @@ -64,7 +137,7 @@ module.exports = async (ctx) => { ); ctx.state.data = { - title: '読売新聞-' + category_name, + title: '読売新聞' + categoryName, link: url, item: items, }; diff --git a/lib/routes/zcool/discover.js b/lib/routes/zcool/discover.js new file mode 100644 index 0000000000..8d02b47393 --- /dev/null +++ b/lib/routes/zcool/discover.js @@ -0,0 +1,140 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const locations = require('./locations'); + +module.exports = async (ctx) => { + const categories = { + 0: '精选', + 8: '平面', + 1: '插画', + 17: 'UI', + 607: '网页', + 33: '摄影', + 24: '三维', + 610: '影视', + 609: '空间', + 499: '工业/产品', + 608: '动漫', + 612: '纯艺术', + 611: '手工艺', + 613: '服装', + 44: '其他', + }; + + const subCategories = { + 0: { 617: '运营设计', 9: '包装', 30: '动画/影视', 34: '人像摄影', 2: '商业插画', 616: '电商', 757: 'APP界面', 292: '艺术插画', 637: '家装设计', 10: '海报', 809824: '文章' }, + 8: { 9: '包装', 10: '海报', 15: '品牌', 779: 'IP形象', 14: '字体/字形', 13: 'Logo', 12: '书籍/画册', 534: '宣传物料', 624: '图案', 625: '信息图表', 626: 'PPT/Keynote', 11: '其他平面', 809: '文章' }, + 1: { 2: '商业插画', 5: '概念设定', 685: '游戏原画', 631: '绘本', 684: '儿童插画', 292: '艺术插画', 7: '创作习作', 3: '新锐潮流插画', 4: '像素画', 819: '文章' }, + 17: { 757: 'APP界面', 692: '游戏UI', 621: '软件界面', 20: '图标', 19: '主题/皮肤', 623: '交互/UE', 797: '动效设计', 21: '闪屏/壁纸', 23: '其他UI ', 822: '文章' }, + 607: { 616: '电商', 614: '企业官网', 693: '游戏/娱乐', 617: '运营设计', 777: '移动端网页', 615: '门户网站', 618: '个人网站', 620: '其他网页', 823: '文章' }, + 33: { 34: '人像摄影', 35: '风光摄影', 36: '人文/纪实摄影', 825: '美食摄影', 686: '产品摄影', 38: '环境/建筑摄影', 800: '时尚/艺术摄影', 687: '修图/后期', 40: '宠物摄影', 808: '婚礼摄影', 43: '其他摄影', 810: '文章' }, + 24: { 30: '动画/影视', 25: '机械/交通', 27: '人物/生物', 807: '产品', 26: '场景', 29: '建筑/空间', 32: '其他三维', 818: '文章' }, + 610: { 645: '短片', 649: 'Motion Graphic', 804: '宣传片', 646: '影视后期', 647: '栏目片头', 644: 'MV', 650: '设定/分镜', 651: '其他影视', 817: '文章' }, + 609: { 637: '家装设计', 811: '酒店餐饮设计', 641: '商业空间设计', 636: '建筑设计', 638: '舞台美术', 639: '展陈设计', 640: '景观设计', 642: '其他空间', 812: '文章' }, + 499: { 508: '生活用品', 506: '电子产品', 509: '交通工具', 511: '工业用品/机械', 510: '人机交互', 689: '玩具', 514: '其他工业/产品', 813: '文章' }, + 608: { 628: '短篇/格漫', 629: '中/长篇漫画', 632: '网络表情', 627: '单幅漫画', 633: '动画片', 635: '其他动漫', 820: '文章' }, + 612: { 659: '绘画', 662: '雕塑', 668: '书法', 657: '实验艺术', 821: '文章' }, + 611: { 654: '工艺品设计', 656: '手办/模玩', 756: '首饰设计', 658: '其他手工艺', 816: '文章' }, + 613: { 672: '休闲/流行服饰', 671: '正装/礼服', 814: '传统/民族服饰', 677: '配饰', 676: '鞋履设计', 673: '儿童服饰', 680: '其他服装', 815: '文章' }, + 44: { 417: '文案/策划', 798: 'VR设计', 683: '独立游戏', 45: '其他', 824: '文章' }, + }; + + const queries = { + cate: '0', + subCate: ctx.params.subCate || '0', + city: ctx.params.city || '0', + college: ctx.params.college || '0', + recommendLevel: ctx.params.recommendLevel || '2', + sort: ctx.params.sort || '9', + }; + + let query = ctx.params.query || ''; + + if (query.indexOf('=') > -1) { + for (const q of query.split('&')) { + const kv = q.split('='); + queries[kv[0]] = kv[1]; + } + queries.limit = '20'; + queries.page = '1'; + } else { + switch (query) { + case 'home': + queries.recommendLevel = '3'; + break; + case 'all': + queries.recommendLevel = '1'; + break; + case 'article': + queries.subCate = '809824'; + queries.recommendLevel = '2'; + break; + case 'editor' || 'edit': + queries.recommendLevel = '2'; + break; + default: + queries.cate = ctx.params.query || '0'; + } + } + + query = ''; + + for (const q in queries) { + if (q === 'city') { + queries[q] = queries[q] in locations ? locations[queries.city].toString() : (queries[q] = '0'); + } + query += `${q}=${queries[q]}&`; + } + + query = query.substr(0, query.length - 1); + + const rootUrl = 'https://www.zcool.com.cn'; + const currentUrl = `${rootUrl}/discover.json?${query}`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const list = response.data.data.data.map((item) => ({ + title: item.object.title, + link: item.object.pageUrl, + pubDate: new Date(item.object.publishTime), + author: item.object.creatorObj.username, + })); + + const items = await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + const content = cheerio.load(detailResponse.data); + + content('.prism-player, .image-info-icons').remove(); + + const videos = detailResponse.data.match(/source: '(https:\/\/video\.zcool\.cn\/.*)',/g); + + let i = 0; + content('.video-content-box').each(function () { + if (i >= videos.length) { + return; + } + content(this).append(`