This commit is contained in:
evnydd0sf
2022-08-31 17:36:29 +08:00
75 changed files with 1077 additions and 461 deletions
+24 -2
View File
@@ -7,15 +7,26 @@ on:
paths:
- '.github/workflows/scrape.yml'
- 'docs/**'
workflow_dispatch: ~
jobs:
scrape-docs:
runs-on: ubuntu-latest
steps:
- name: Wait for Netlify to finish
run: sleep 3m
- name: Checkout
uses: actions/checkout@v3
- name: Use Node.js v16
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
- name: Install dependencies (yarn)
run: yarn
- name: Pull image
run: docker pull getmeili/docs-scraper
- name: Wait for Netlify to finish
run: sleep 3m
if: github.event_name == 'push'
- name: Run docs-scraper
env:
HOST_URL: ${{ secrets.MEILISEARCH_HOST_URL }}
@@ -27,3 +38,14 @@ jobs:
-e MEILISEARCH_API_KEY=$API_KEY \
-v $CONFIG_FILE_PATH:/docs-scraper/config.json \
getmeili/docs-scraper pipenv run ./docs_scraper config.json
- name: Update meilisearch settings
uses: actions/github-script@v6
env:
HOST_URL: ${{ secrets.MEILISEARCH_HOST_URL }}
API_KEY: ${{ secrets.MEILISEARCH_API_KEY }}
with:
script: |
const meilisearchHost = process.env.HOST_URL
const meilisearchApiKey = process.env.API_KEY
const script = require(`${process.env.GITHUB_WORKSPACE}/scripts/docs-scraper/settings.js`)
await script({ core }, meilisearchHost, meilisearchApiKey)
-26
View File
@@ -34,21 +34,6 @@
s: [{ title: '热搜榜', docs: 'https://docs.rsshub.app/social-media.html#wei-bo', source: '/top/summary', target: '/weibo/search/hot' }],
},
'weibo.cn': { _name: '微博', m: [{ title: '博主', docs: 'https://docs.rsshub.app/social-media.html#wei-bo', source: ['/u/:uid', '/profile/:uid'], target: '/weibo/user/:uid' }] },
'pixiv.net': {
_name: 'Pixiv',
www: [
{ title: '用户收藏', docs: 'https://docs.rsshub.app/social-media.html#pixiv', source: '/users/:id/bookmarks/artworks', target: '/pixiv/user/bookmarks/:id' },
{ title: '用户动态', docs: 'https://docs.rsshub.app/social-media.html#pixiv', source: '/users/:id', target: '/pixiv/user/:id' },
{ title: '排行榜', docs: 'https://docs.rsshub.app/social-media.html#pixiv', source: '/ranking.php', target: (params, url) => `/pixiv/ranking/${new URL(url).searchParams.get('mode') || 'daily'}` },
{
title: '关键词',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: ['/tags/:keyword', '/tags/:keyword/:type?'],
target: (params, url) => `/pixiv/search/:keyword/${new URL(url).searchParams.get('order')}/${new URL(url).searchParams.get('mode')}`,
},
{ title: '关注的新作品', docs: 'https://docs.rsshub.app/social-media.html#pixiv', source: '/bookmark_new_illust.php', target: '/pixiv/user/illustfollows' },
],
},
'github.com': {
_name: 'GitHub',
'.': [
@@ -322,17 +307,6 @@
],
sites: [{ title: 'Sites', docs: 'https://docs.rsshub.app/blog.html#google-sites', source: ['/site/:id/*', '/site/:id'], target: '/google/sites/:id' }],
},
'qidian.com': {
_name: '起点',
book: [
{ title: '章节', docs: 'https://docs.rsshub.app/reading.html#qi-dian', source: '/info/:id', target: '/qidian/chapter/:id' },
{ title: '讨论区', docs: 'https://docs.rsshub.app/reading.html#qi-dian', source: '/info/:id', target: '/qidian/forum/:id' },
],
www: [
{ title: '限免', docs: 'https://docs.rsshub.app/reading.html#qi-dian', source: '/free', target: '/qidian/free' },
{ title: '女生限免', docs: 'https://docs.rsshub.app/reading.html#qi-dian', source: '/mm/free', target: '/qidian/free/mm' },
],
},
'hackerone.com': { _name: 'HackerOne', '.': [{ title: 'HackerOne Hacker Activity', docs: 'https://docs.rsshub.app/other.html#hackerone-hacker-activity', source: '/hacktivity', target: '/hackerone/hacktivity' }] },
'cowlevel.net': { _name: '奶牛关', '.': [{ title: '元素文章', docs: 'https://docs.rsshub.app/game.html#nai-niu-guan', source: ['/element/:id', '/element/:id/article'], target: '/cowlevel/element/:id' }] },
'beijing.gov.cn': { wjw: [{ title: '北京卫生健康委员会', docs: 'https://docs.rsshub.app/government.html#bei-jing-shi-wei-sheng-jian-kang-wei-yuan-hui', source: '/xwzx_20031/:caty', target: '/gov/beijing/mhc/:caty' }] },
+15 -1
View File
@@ -363,7 +363,21 @@ Sources
### Love Live 官网最新 News
<Route author="axojhf" example="/lovelive-anime/news" path="/lovelive-anime/news/:option?" :paramsDesc="['`option` 为 `detail` 时抓取全文']" />
<Route author="axojhf" example="/lovelive-anime/news" path="/lovelive-anime/news/:option?" :paramsDesc="['`option` 为 `detail` 时抓取全文']" radar="1"/>
### Love Live 官网分类 Topics
<Route author="axojhf" example="/lovelive-anime/topics/otonokizaka" path="/lovelive-anime/topics/:abbr/:category?/:option?" :paramsDesc="['Love Live系列子企划在官网的路径,详见下表', '官网列出的Topics分类,`category` 为 `detail` 时抓取全文,其他分类详见下表', '`option` 为 `detail` 时抓取全文']" radar="1">
| 子企划名(非全称) | Lovelive! | Lovelive! Sunshine!! | Lovelive! Nijigasaki High School Idol Club | Lovelive! Superstar!! |
| --------- | ----------- | -------------------- | ------------------------------------------ | --------------------- |
| `abbr`参数 | otonokizaka | uranohoshi | nijigasaki | yuigaoka |
| 分类名 | 全てのニュース | 音楽商品 | アニメ映像商品 | キャスト映像商品 | 劇場 | アニメ放送 / 配信 | キャスト配信 / ラジオ | ライブ / イベント | ブック | グッズ | ゲーム | メディア | ご当地情報 | その他 | キャンペーン |
| ------------ | ------------ | ----- | ----------- | ---------- | ------- | ---------- | ------------ | ---------- | ----- | ----- | ---- | ----- | ----- | ----- | -------- |
| `category`参数 | <u>*无参数*</u> | music | anime_movie | cast_movie | theater | onair | radio | event | books | goods | game | media | local | other | campaign |
</Route>
## Mox.moe
+16 -1
View File
@@ -72,7 +72,22 @@ When `posts` is selected as the value of the parameter **source**, the parameter
### Love Live! Official Website Latest NEWS
<RouteEn author="axojhf" example="/lovelive-anime/news" path="/lovelive-anime/news/:option?" :paramsDesc="['Crawl full text when `option` is `detail`.']" />
<RouteEn author="axojhf" example="/lovelive-anime/news" path="/lovelive-anime/news/:option?" :paramsDesc="['Crawl full text when `option` is `detail`.']" radar="1"/>
### Love Live Official Website Categories Topics
<RouteEn author="axojhf" example="/lovelive-anime/topics/otonokizaka" path="/lovelive-anime/topics/:abbr/:category?/:option?" :paramsDesc="['The path to the Love Live series of sub-projects on the official website is detailed in the table below', 'The official website lists the Topics category, `category` is `detail` when crawling the full text, other categories see the following table for details', 'Crawl full text when `option` is `detail`.']" radar="1">
| Sub-project name (not full name) | Lovelive! | Lovelive! Sunshine!! | Lovelive! Nijigasaki High School Idol Club | Lovelive! Superstar!! |
| -------------------------------- | ----------- | -------------------- | ------------------------------------------ | --------------------- |
| `abbr`parameter | otonokizaka | uranohoshi | nijigasaki | yuigaoka |
| category name | 全てのニュース | 音楽商品 | アニメ映像商品 | キャスト映像商品 | 劇場 | アニメ放送/配信 | キャスト配信/ラジオ | ライブ/イベント | ブック | グッズ | ゲーム | メディア | ご当地情報 | その他 | キャンペーン |
| -------------- | --------------- | -------- | -------------- | ---------------- | ------- | --------------- | ------------------- | --------------- | ------ | ------ | ------ | -------- | ---------- | ------ | ------------ |
| `category`parameter | <u>*No parameter*</u> | music | anime_movie | cast_movie | theater | onair | radio | event | books | goods | game | media | local | other | campaign |
</RouteEn>
## Touhougarakuta
+1 -1
View File
@@ -236,7 +236,7 @@ Language
### Script Update
<RouteEn author="imlonghao" path="/greasyfork/:language/:domain?" example="/greasyfork/en/google.com" :paramsDesc="['language, located on the top right corner of Greasy Fork\'s search page, set to `all` for including all languages', 'the script\'s target domain']" />
<RouteEn author="imlonghao" path="/greasyfork/:language/:domain?" example="/greasyfork/en/google.com" :paramsDesc="['language, located on the top right corner of Greasy Fork\'s search page, set to `all` for including all languages', 'the script\'s target domain']" radar="1" />
## Hugo
+4
View File
@@ -214,6 +214,10 @@ Though, every Story expires after 24 hours, so it may be not so serious.
<RouteEn author="EYHN" path="/pixiv/user/:id" example="/pixiv/user/15288095" :paramsDesc="['user id, available in user\'s homepage URL']" radar="1" rssbud="1"/>
### User Novels
<RouteEn author="TonyRL" example="/pixiv/user/novels/27104704" path="/pixiv/user/novels/:id" :paramsDesc="['User id, available in user\'s homepage URL']" radar="1" rssbud="1"/>
### Rankings
<RouteEn author="EYHN" path="/pixiv/ranking/:mode/:date?" example="/pixiv/ranking/week" :paramsDesc="['rank type', 'format: `2018-4-25`']" radar="1" rssbud="1">
+1 -1
View File
@@ -268,7 +268,7 @@ pageClass: routes
### 脚本更新
<Route author="imlonghao" example="/greasyfork/zh-CN/bilibili.com" path="/greasyfork/:language/:domain?" :paramsDesc="['语言, 可在网站右上角找到, `all` 为所有语言', '按脚本生效域名过滤, 可选']"/>
<Route author="imlonghao" example="/greasyfork/zh-CN/bilibili.com" path="/greasyfork/:language/:domain?" :paramsDesc="['语言, 可在网站右上角找到, `all` 为所有语言', '按脚本生效域名过滤, 可选']" radar="1"/>
## Hugo
+4
View File
@@ -399,6 +399,10 @@ count 的取值范围为 1-12,为防止请求次数过多,推荐设置为 5
<Route author="LogicJake" example="/qidian/free-next" path="/qidian/free-next/:type?" :paramsDesc="['默认不填为起点中文网,填 mm 为起点女生网']"/>
### 作者
<Route author="miles170" example="/qidian/author/9639927" path="/qidian/author/:id" :paramsDesc="['作者 id, 可在作者页面 URL 找到']"/>
## 起点图
### 首订
+4
View File
@@ -562,6 +562,10 @@ Instagram Stories 没有可靠的 guid,你的 RSS 阅读器可能将同一条
<Route author="DIYgod" example="/pixiv/user/11" path="/pixiv/user/:id" :paramsDesc="['用户 id, 可在用户主页 URL 中找到']" radar="1" rssbud="1"/>
### 用户小说
<Route author="TonyRL" example="/pixiv/user/novels/27104704" path="/pixiv/user/novels/:id" :paramsDesc="['用户 id, 可在用户主页 URL 中找到']" radar="1" rssbud="1"/>
### 排行榜
<Route author="EYHN" example="/pixiv/ranking/week" path="/pixiv/ranking/:mode/:date?" :paramsDesc="['排行榜类型' ,'日期, 取值形如 `2018-4-25`']" radar="1" rssbud="1">
+24
View File
@@ -1152,6 +1152,18 @@ Type 栏目:
</Route>
## 華視
### 新聞
<Route author="miles170" example="/cts/real" path="/cts/:category" :paramsDesc="['类别']" radar="1">
| 即時 | 氣象 | 政治 | 國際 | 社會 | 運動 | 生活 | 財經 | 台語 | 地方 | 產業 | 綜合 | 藝文 | 娛樂 |
| ---- | ------- | -------- | ------------- | ------- | ------ | ---- | ----- | --------- | ----- | -- | ------- | ---- | --------- |
| real | weather | politics | international | society | sports | life | money | taiwanese | local | pr | general | arts | entertain |
</Route>
## 环球网
### 分类
@@ -1364,6 +1376,18 @@ category 对应的关键词有
<Route author="shunf4" example="/zaobao/interactive-graphics" path="/zaobao/interactive-graphics" />
## 聯合新聞網
### 即時新聞
<Route author="miles170" example="/udn/news/breakingnews/99" path="/udn/news/breakingnews/:id" :paramsDesc="['类别']" radar="1">
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 99 |
| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | --- |
| 精選 | 要聞 | 社會 | 地方 | 兩岸 | 國際 | 財經 | 運動 | 娛樂 | 生活 | 股市 | 文教 | 數位 | 不分類 |
</Route>
## 路透社
::: warning 迁移说明
+20 -12
View File
@@ -1811,7 +1811,7 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE_TLS
### 教务处
<Route author="arcosx Seiry qrzbing" example="/nuaa/jwc/tzgg" path="/nuaa/jwc/:type/:getDescription?" :paramsDesc="['分类名', '是否获取描述']" puppeteer="1">
<Route author="arcosx Seiry qrzbing Xm798" example="/nuaa/jwc/tzgg/getDescription" path="/nuaa/jwc/:type/:getDescription?" :paramsDesc="['分类名,见下表', '是否获取全文']" puppeteer="1" radar="1">
| 通知公告 | 教学服务 | 教学建设 | 学生培养 | 教学资源 |
| ---- | ---- | ---- | ---- | ---- |
@@ -1819,9 +1819,27 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE_TLS
</Route>
### 研究生院
<Route author="junfengP Seiry Xm798" example="/nuaa/yjsy/tzgg/getDescription" path="/nuaa/yjsy/:type/:getDescription?" :paramsDesc="['分类名,见下表', '是否获取全文']" puppeteer="1" radar="1">
| 通知公告 | 新闻动态 | 学术信息 | 师生风采 |
| ---- | ---- | ---- | ---- |
| tzgg | xwdt | xsxx | ssfc |
</Route>
### 自动化学院
<Route author="Xm798" example="/nuaa/cae/zhxw" path="/nuaa/cs/:type/:getDescription?" :paramsDesc="['分类名,见下表', '是否获取全文']" puppeteer="1" radar="1">
| 综合新闻 | 党委行政 | 人事 / 合作 | 研究生培养 | 本科生培养 | 学生工作 | 通知公告 | 学术信息 | 答辩公告 |
| ---- | ---- | ------- | ----- | ----- | ---- | ---- | ---- | ---- |
| zhxw | dwxz | rshz | yjs | bks | xsgz | tzgg | xsxx | dbgg |
### 计算机科学与技术学院
<Route author="LogicJake Seiry qrzbing" example="/nuaa/cs/jxdt" path="/nuaa/cs/:type/:getDescription?" :paramsDesc="['分类名', '是否获取描述']" puppeteer="1">
<Route author="LogicJake Seiry qrzbing Xm798" example="/nuaa/cs/jxdt" path="/nuaa/cs/:type/:getDescription?" :paramsDesc="['分类名,见下表', '是否获取全文']" puppeteer="1" radar="1">
| 通知公告 | 热点新闻 | 学科科研 | 教学动态 | 本科生培养 | 研究生培养 | 学生工作 |
| ---- | ---- | ---- | ---- | ----- | ----- | ---- |
@@ -1829,16 +1847,6 @@ jsjxy.hbut.edu.cn 证书链不全,自建 RSSHub 可设置环境变量 NODE_TLS
</Route>
### 研究生院
<Route author="junfengP Seiry" example="/nuaa/yjsy/latest" path="/nuaa/yjsy/:type?" :paramsDesc="['分类名']"/>
| 最近动态 | 研院新闻 | 上级文件 | 管理文件 | 信息服务 |
| ------ | ---- | ---- | ---- | ---- |
| latest | yyxw | sjwj | glwj | xxfw |
</Route>
## 南京理工大学
### 教务处
-66
View File
@@ -45,41 +45,6 @@ module.exports = {
},
],
},
'pixiv.net': {
_name: 'Pixiv',
www: [
{
title: '用户收藏',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/users/:id/bookmarks/artworks',
target: '/pixiv/user/bookmarks/:id',
},
{
title: '用户动态',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/users/:id',
target: '/pixiv/user/:id',
},
{
title: '排行榜',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/ranking.php',
target: (params, url) => `/pixiv/ranking/${new URL(url).searchParams.get('mode') || 'daily'}`,
},
{
title: '关键词',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: ['/tags/:keyword', '/tags/:keyword/:type?'],
target: (params, url) => `/pixiv/search/:keyword/${new URL(url).searchParams.get('order')}/${new URL(url).searchParams.get('mode')}`,
},
{
title: '关注的新作品',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/bookmark_new_illust.php',
target: '/pixiv/user/illustfollows',
},
],
},
'smzdm.com': {
_name: '什么值得买',
www: [
@@ -782,37 +747,6 @@ module.exports = {
},
],
},
'qidian.com': {
_name: '起点',
book: [
{
title: '章节',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/info/:id',
target: '/qidian/chapter/:id',
},
{
title: '讨论区',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/info/:id',
target: '/qidian/forum/:id',
},
],
www: [
{
title: '限免',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/free',
target: '/qidian/free',
},
{
title: '女生限免',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/mm/free',
target: '/qidian/free/mm',
},
],
},
'hackerone.com': {
_name: 'HackerOne',
'.': [
+13 -13
View File
@@ -116,12 +116,12 @@ router.get('/mzitu/category/:category', lazyloadRouteHandler('./routes/mzitu/cat
router.get('/mzitu/post/:id', lazyloadRouteHandler('./routes/mzitu/post'));
router.get('/mzitu/tag/:tag', lazyloadRouteHandler('./routes/mzitu/tag'));
// pixiv
router.get('/pixiv/user/bookmarks/:id', lazyloadRouteHandler('./routes/pixiv/bookmarks'));
router.get('/pixiv/user/illustfollows', lazyloadRouteHandler('./routes/pixiv/illustfollow'));
router.get('/pixiv/user/:id', lazyloadRouteHandler('./routes/pixiv/user'));
router.get('/pixiv/ranking/:mode/:date?', lazyloadRouteHandler('./routes/pixiv/ranking'));
router.get('/pixiv/search/:keyword/:order?/:mode?', lazyloadRouteHandler('./routes/pixiv/search'));
// pixiv migrated to v2
// router.get('/pixiv/user/bookmarks/:id', lazyloadRouteHandler('./routes/pixiv/bookmarks'));
// router.get('/pixiv/user/illustfollows', lazyloadRouteHandler('./routes/pixiv/illustfollow'));
// router.get('/pixiv/user/:id', lazyloadRouteHandler('./routes/pixiv/user'));
// router.get('/pixiv/ranking/:mode/:date?', lazyloadRouteHandler('./routes/pixiv/ranking'));
// router.get('/pixiv/search/:keyword/:order?/:mode?', lazyloadRouteHandler('./routes/pixiv/search'));
// pixiv-fanbox
router.get('/fanbox/:user?', lazyloadRouteHandler('./routes/fanbox/main'));
@@ -338,11 +338,11 @@ router.get('/mi/bbs/board/:boardId', lazyloadRouteHandler('./routes/mi/board'));
// Keep
// router.get('/keep/user/:id', lazyloadRouteHandler('./routes/keep/user'));
// 起点
router.get('/qidian/chapter/:id', lazyloadRouteHandler('./routes/qidian/chapter'));
router.get('/qidian/forum/:id', lazyloadRouteHandler('./routes/qidian/forum'));
router.get('/qidian/free/:type?', lazyloadRouteHandler('./routes/qidian/free'));
router.get('/qidian/free-next/:type?', lazyloadRouteHandler('./routes/qidian/free-next'));
// 起点 migrated to v2
// router.get('/qidian/chapter/:id', lazyloadRouteHandler('./routes/qidian/chapter'));
// router.get('/qidian/forum/:id', lazyloadRouteHandler('./routes/qidian/forum'));
// router.get('/qidian/free/:type?', lazyloadRouteHandler('./routes/qidian/free'));
// router.get('/qidian/free-next/:type?', lazyloadRouteHandler('./routes/qidian/free-next'));
// 纵横
router.get('/zongheng/chapter/:id', lazyloadRouteHandler('./routes/zongheng/chapter'));
@@ -387,8 +387,8 @@ router.get('/xuangubao/subject/:subject_id', lazyloadRouteHandler('./routes/xuan
// router.get('/xueqiu/hots', lazyloadRouteHandler('./routes/xueqiu/hots'));
// router.get('/xueqiu/stock_comments/:id/:titleLength?', lazyloadRouteHandler('./routes/xueqiu/stock_comments'));
// Greasy Fork
router.get('/greasyfork/:language/:domain?', lazyloadRouteHandler('./routes/greasyfork/scripts'));
// Greasy Fork migrated to v2
// router.get('/greasyfork/:language/:domain?', lazyloadRouteHandler('./routes/greasyfork/scripts'));
// Gwern Bran­wen
router.get('/gwern/:category', lazyloadRouteHandler('./routes/gwern/category'));
+1
View File
@@ -85,6 +85,7 @@ module.exports = async (ctx) => {
ctx.state.data = {
title,
link,
image: 'https://www.bbc.com/favicon.ico',
description: title,
item: items,
};
-74
View File
@@ -1,74 +0,0 @@
const config = require('@/config').value;
const logger = require('@/utils/logger');
const got = require('./pixiv-got');
const { maskHeader } = require('./constants');
let token = null;
const authorizationInfo = {
client_id: 'MOBrBDS8blbauoSck0ZfDbtuzpyT',
client_secret: 'lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj',
hash_secret: '28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c',
};
const refreshToken = () =>
got({
method: 'post',
url: 'https://oauth.secure.pixiv.net/auth/token',
form: {
...authorizationInfo,
get_secure_url: 1,
grant_type: 'refresh_token',
refresh_token: config.pixiv.refreshToken,
},
headers: {
...maskHeader,
},
responseType: 'json',
resolveBodyOnly: true,
}).catch((e) => {
logger.error('Pixiv refresh token failed.');
logger.debug(e);
});
async function tickToken() {
const result = await refreshToken();
let expireTime;
if (result && result.access_token) {
logger.debug('Pixiv refresh token success.');
token = result.access_token;
expireTime = result.expires_in;
} else {
expireTime = 30;
logger.error(`Pixiv refresh token failed, retry in ${expireTime} seconds.`);
}
// If is package, the mock server should be closed after request, needn't to refresh
if (!config.isPackage) {
setTimeout(tickToken, expireTime);
}
}
let tickTokenStarted = false;
async function startTickToken() {
if (!tickTokenStarted) {
// 如果tickToken没启动
tickTokenStarted = true;
await tickToken(); // 启动tickToken
}
}
async function waitForToken() {
while (!token) {
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => setTimeout(resolve, 0));
}
return token;
}
module.exports = async () => {
await startTickToken();
return waitForToken();
};
module.exports.tickToken = tickToken;
+1 -2
View File
@@ -39,13 +39,12 @@ module.exports = async (ctx) => {
.toArray()
.map((element) => {
const item = $(element);
return `<img src="${item.attr('bpic').split('?tbpicau')[0]}">`;
return `<img src="${item.attr('bpic')?.split('?tbpicau')[0]}">`;
})
.join('');
return {
title,
// description: `<p>${details}</p><p>${medias}</p><p>作者:${author_name}</p>`,
description: art(path.join(__dirname, '../templates/forum.art'), {
details,
medias,
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
'/:category': ['miles170'],
};
+40
View File
@@ -0,0 +1,40 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const asyncPool = require('tiny-async-pool');
module.exports = async (ctx) => {
const category = ctx.params.category;
const currentUrl = `https://news.cts.com.tw/${category}/index.html`;
const response = await got(currentUrl);
const $ = cheerio.load(response.data);
const items = [];
for await (const data of asyncPool(5, $('#newslist-top a[title]').slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 20), (item) => {
item = $(item);
const link = item.attr('href');
return ctx.cache.tryGet(link, async () => {
const response = await got(link);
const $ = cheerio.load(response.data);
const author = $('.artical-content p:eq(0)').text().trim();
$('.artical-content p:eq(0), .artical-content .flexbox').remove();
return {
title: item.attr('title'),
author,
description: $('.artical-content').html(),
category: $('meta[property="article:section"]').attr('content'),
pubDate: parseDate($('meta[property="article:published_time"]').attr('content')),
link,
};
});
})) {
items.push(data);
}
ctx.state.data = {
title: $('title').text(),
link: currentUrl,
description: $('meta[name="description"]').attr('content'),
item: items,
};
};
+13
View File
@@ -0,0 +1,13 @@
module.exports = {
'cts.com.tw': {
_name: '華視',
news: [
{
title: '新聞',
docs: 'https://docs.rsshub.app/traditional-media.html#hua-shi-xin-wen',
source: '/:category/index.html',
target: '/cts/:category',
},
],
},
};
+3
View File
@@ -0,0 +1,3 @@
module.exports = function (router) {
router.get('/:category', require('./news'));
};
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
'/:language/:domain?': ['imlonghao', 'miles170'],
};
+13
View File
@@ -0,0 +1,13 @@
module.exports = {
'greasyfork.org': {
_name: 'Greasy Fork',
'.': [
{
title: 'User scripts',
docs: 'https://docs.rsshub.app/program-update.html#greasy-fork',
source: ['/:language', '/:language/scripts/by-site/:domain?'],
target: '/greasyfork/:language/:domain?',
},
],
},
};
+3
View File
@@ -0,0 +1,3 @@
module.exports = (router) => {
router.get('/:language/:domain?', require('./scripts'));
};
@@ -7,10 +7,10 @@ module.exports = async (ctx) => {
const domain = ctx.params.domain;
const filter_locale = ctx.params.language === 'all' ? 0 : 1;
const url = domain ? `by-site/${domain}` : '';
const currentUrl = `https://greasyfork.org/${language}/scripts/${url}`;
const res = await got({
method: 'get',
url: `https://greasyfork.org/${language}/scripts/${url}`,
url: currentUrl,
searchParams: queryString.stringify({
filter_locale,
sort: 'updated',
@@ -21,12 +21,12 @@ module.exports = async (ctx) => {
ctx.state.data = {
title: $('title').first().text(),
link: `https://greasyfork.org/${language}/scripts/${url}`,
link: currentUrl,
description: $('meta[name=description]').attr('content'),
item:
list &&
list
.map((index, item) => {
.map((_, item) => {
item = $(item);
return {
title: item.find('a').text(),
+1
View File
@@ -1,3 +1,4 @@
module.exports = {
'/news/:option?': ['axojhf'],
'/topics/:abbr/:category?': ['axojhf'],
};
+12 -3
View File
@@ -3,11 +3,20 @@ module.exports = {
_name: 'Love Live 官网',
www: [
{
title: '最新NEWS',
docs: 'https://docs.rsshub.app/anime.html#lovelive-anime',
source: ['/'],
title: '最新 NEWS',
docs: 'https://docs.rsshub.app/anime.html#lovelive-anime-love-live-guan-wang-zui-xin-news',
source: ['/', '/news'],
target: '/lovelive-anime/news',
},
{
title: '分类 Topics',
docs: 'https://docs.rsshub.app/anime.html#lovelive-anime-love-live-guan-wang-fen-lei-topics',
source: ['/:abbr/topics/', '/:abbr/topics.php'],
target: (params, url) => {
const cat = url.match(/\?cat=(.*)/);
return `/lovelive-anime/topics/${params.abbr}/${null !== cat && cat.length === 2 ? cat[1] : ''}`;
},
},
],
},
};
+1
View File
@@ -1,3 +1,4 @@
module.exports = (router) => {
router.get('/news/:option?', require('./news'));
router.get('/topics/:abbr/:category?/:option?', require('./topics'));
};
+84
View File
@@ -0,0 +1,84 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const path = require('path');
const { art } = require('@/utils/render');
const { parseDate } = require('@/utils/parse-date');
const renderDescription = (desc) => art(path.join(__dirname, 'templates/description.art'), desc);
module.exports = async (ctx) => {
const abbr = ctx.params.abbr;
const rootUrl = `https://www.lovelive-anime.jp/${abbr}`;
const topicsUrlPart = 'yuigaoka' === abbr ? 'topics/' : 'topics.php';
const baseUrl = `${rootUrl}/${'yuigaoka' === abbr ? 'topics/' : ''}`;
const abbrDetail = {
otonokizaka: 'ラブライブ!',
uranohoshi: 'サンシャイン!!',
nijigasaki: '虹ヶ咲学園',
yuigaoka: 'スーパースター!!',
};
let url;
if (ctx.params.hasOwnProperty('category') && ctx.params.category !== 'detail') {
url = `${rootUrl}/${topicsUrlPart}?cat=${ctx.params.category}`;
} else {
url = `${rootUrl}/${topicsUrlPart}`;
}
const response = await got(url);
const $ = cheerio.load(response.data);
const categoryName = 'uranohoshi' === abbr ? $('div.llbox > p').text() : $('div.category_title > h2').text();
let items = $('ul.listbox > li')
.map((_, item) => {
item = $(item);
const link = `${baseUrl}${item.find('div > a').attr('href')}`;
const pubDate = parseDate(item.find('a > p.date').text(), 'YYYY/MM/DD');
const title = item.find('a > p.title').text();
const category = item.find('a > p.category').text();
const imglink = `${baseUrl}${
item
.find('a > img')
.attr('style')
.match(/background-image:url\((.*)\)/)[1]
}`;
return {
link,
pubDate,
title,
category,
description: renderDescription({
title,
imglink,
}),
};
})
.get();
if (ctx.params.option === 'detail' || ctx.params.category === 'detail') {
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResp = await got(item.link);
const $ = cheerio.load(detailResp.data);
const content = $('div.p-page__detail.p-article');
for (const v of content.find('img')) {
v.attribs.src = `${baseUrl}${v.attribs.src}`;
}
item.description = content.html();
return item;
})
)
);
}
ctx.state.data = {
title: `${categoryName} - ${abbrDetail[abbr]} - Love Live Official Website Topics`,
link: url,
item: items,
};
};
+79
View File
@@ -0,0 +1,79 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const getCookie = require('../utils/pypasswaf');
const host = 'https://cae.nuaa.edu.cn/';
const map = new Map([
['zhxw', { title: '综合新闻 | 南京航空航天大学自动化学院', suffix: '5399/list.htm' }],
['dwxz', { title: '党委行政 | 南京航空航天大学自动化学院', suffix: '13266/list.htm' }],
['rshz', { title: '人事/合作 | 南京航空航天大学自动化学院', suffix: '13267/list.htm' }],
['yjs', { title: '研究生培养 | 南京航空航天大学自动化学院', suffix: '13271/list.htm' }],
['bks', { title: '本科生培养 | 南京航空航天大学自动化学院', suffix: '13270/list.htm' }],
['xsgz', { title: '学生工作 | 南京航空航天大学自动化学院', suffix: '13268/list.htm' }],
['tzgg', { title: '通知公告 | 南京航空航天大学自动化学院', suffix: '13264/list.htm' }],
['xsxx', { title: '学术信息 | 南京航空航天大学自动化学院', suffix: '13265/list.htm' }],
['dbgg', { title: '答辩公告 | 南京航空航天大学自动化学院', suffix: 'dbgg/list.htm' }],
]);
module.exports = async (ctx) => {
const type = ctx.params.type;
const suffix = map.get(type).suffix;
const getDescription = Boolean(ctx.params.getDescription) || false;
const link = new URL(suffix, host).href;
const cookie = await getCookie(host);
const gotConfig = {
headers: {
cookie,
},
};
const response = await got(link, gotConfig);
const $ = cheerio.load(response.data);
const list = $('#wp_news_w6 ul li')
.slice(0, 10)
.map(function () {
const info = {
title: $(this).find('a').text(),
link: $(this).find('a').attr('href'),
date: $(this).find('span').text(),
};
return info;
})
.get();
const out = await Promise.all(
list.map(async (info) => {
const title = info.title || 'tzgg';
const date = info.date;
const itemUrl = new URL(info.link, host).href;
let description = title + '<br><a href="' + itemUrl + '" target="_blank">查看原文</a>';
if (getDescription) {
description = await ctx.cache.tryGet(itemUrl, async () => {
const arr = itemUrl.split('.');
const pageType = arr[arr.length - 1];
if (pageType === 'htm' || pageType === 'html') {
const response = await got(itemUrl, gotConfig);
const $ = cheerio.load(response.data);
return $('.wp_articlecontent').html() + '<br><hr /><a href="' + itemUrl + '" target="_blank">查看原文</a>';
}
});
}
return {
title,
link: itemUrl,
description,
pubDate: parseDate(date),
};
})
);
ctx.state.data = {
title: map.get(type).title,
link,
description: '南京航空航天大学自动化学院RSS',
item: out,
};
};
+78
View File
@@ -0,0 +1,78 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const getCookie = require('../utils/pypasswaf');
const host = 'https://cs.nuaa.edu.cn/';
const map = new Map([
['tzgg', { title: '通知公告 | 南京航空航天大学计算机科学与技术学院', suffix: 'tzgg/list.htm' }],
['rdxw', { title: '热点新闻 | 南京航空航天大学计算机科学与技术学院', suffix: '10846/list.htm' }],
['xkky', { title: '学科科研 | 南京航空航天大学计算机科学与技术学院', suffix: '10849/list.htm' }],
['be', { title: '本科生培养 | 南京航空航天大学计算机科学与技术学院', suffix: '10850/list.htm' }],
['me', { title: '研究生培养 | 南京航空航天大学计算机科学与技术学院', suffix: '10851/list.htm' }],
['jxdt', { title: '教学动态 | 南京航空航天大学计算机科学与技术学院', suffix: '1977/list.htm' }],
['xsgz', { title: '学生工作 | 南京航空航天大学计算机科学与技术学院', suffix: '1959/list.htm' }],
]);
module.exports = async (ctx) => {
const type = ctx.params.type;
const getDescription = Boolean(ctx.params.getDescription) || false;
const suffix = map.get(type).suffix;
const link = new URL(suffix, host).href;
const cookie = await getCookie(host);
const gotConfig = {
headers: {
cookie,
},
};
const response = await got(link, gotConfig);
const $ = cheerio.load(response.data);
const list = $('#news_list ul li')
.slice(0, Math.min(parseInt($('.per_count', '#wp_paging_w6').text()), parseInt($('.all_count', '#wp_paging_w6').slice(1).text())))
.map(function () {
const info = {
title: $(this).find('a').attr('title'),
link: $(this).find('a').attr('href'),
date: $(this).find('span').text(),
};
return info;
})
.get();
const out = await Promise.all(
list.map(async (info) => {
const title = info.title || 'tzgg';
const date = info.date;
const itemUrl = new URL(info.link, host).href;
let description = title + '<br><a href="' + itemUrl + '" target="_blank">查看原文</a>';
if (getDescription) {
description = await ctx.cache.tryGet(itemUrl, async () => {
const arr = itemUrl.split('.');
const pageType = arr[arr.length - 1];
if (pageType === 'htm' || pageType === 'html') {
const response = await got(itemUrl, gotConfig);
const $ = cheerio.load(response.data);
return $('.wp_articlecontent').html() + '<br><hr /><a href="' + itemUrl + '" target="_blank">查看原文</a>';
}
});
}
return {
title,
link: itemUrl,
description,
pubDate: parseDate(date),
};
})
);
ctx.state.data = {
title: map.get(type).title,
link,
description: '南京航空航天大学计算机科学与技术学院RSS',
item: out,
};
};
-87
View File
@@ -1,87 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const getCookie = require('../utils/pypasswaf');
const host = 'http://cs.nuaa.edu.cn/';
const map = new Map([
['tzgg', { title: '南京航空航天大学计算机科学与技术学院 -- 通知公告', suffix: 'tzgg/list.htm' }],
['rdxw', { title: '南京航空航天大学计算机科学与技术学院 -- 热点新闻', suffix: '10846/list.htm' }],
['xkky', { title: '南京航空航天大学计算机科学与技术学院 -- 学科科研', suffix: '10849/list.htm' }],
['be', { title: '南京航空航天大学计算机科学与技术学院 -- 本科生培养', suffix: '10850/list.htm' }],
['me', { title: '南京航空航天大学计算机科学与技术学院 -- 研究生培养', suffix: '10851/list.htm' }],
['jxdt', { title: '南京航空航天大学计算机科学与技术学院 -- 教学动态', suffix: '1977/list.htm' }],
['xsgz', { title: '南京航空航天大学计算机科学与技术学院 -- 学生工作', suffix: '1959/list.htm' }],
]);
module.exports = async (ctx) => {
const type = ctx.params.type;
const getDescription = Boolean(ctx.params.getDescription) || false;
const suffix = map.get(type).suffix;
const link = new URL(suffix, host).href;
const cookie = await getCookie();
const gotConfig = {
headers: {
cookie,
},
};
const response = await got(link, gotConfig);
const $ = cheerio.load(response.data);
const list = $('#news_list ul li')
.slice(0, Math.min(parseInt($('.per_count', '#wp_paging_w6').text()), parseInt($('.all_count', '#wp_paging_w6').slice(1).text())))
.map(function () {
const info = {
title: $(this).find('a').attr('title'),
link: $(this).find('a').attr('href'),
date: $(this).find('span').text(),
};
return info;
})
.get();
const out = await Promise.all(
list.map((info) => {
const title = info.title || 'tzgg';
const date = info.date;
const itemUrl = new URL(info.link, host).href;
return ctx.cache.tryGet(itemUrl, async () => {
const arr = itemUrl.split('.');
const pageType = arr[arr.length - 1];
// 南航新 WAF 过于敏感
// 目前 description 需要遍历页面,会被 WAF 拦截导致无法输出
// 考虑换一种获取 description 的方式或者将标题当作 title。
let description = title;
if (getDescription) {
description = itemUrl;
if (pageType === 'htm' || pageType === 'html') {
const response = await got.get(itemUrl, gotConfig);
const $ = cheerio.load(response.data);
description = $('.wp_articlecontent')
.html()
.replace(/src="\//g, `src="${new URL('.', host).href}`)
.trim();
}
}
const single = {
title,
link: itemUrl,
description,
pubDate: parseDate(date),
};
return single;
});
})
);
ctx.state.data = {
title: map.get(type).title,
link,
description: '南京航空航天大学计算机科学与技术学院RSS',
item: out,
};
};
+21 -27
View File
@@ -5,11 +5,11 @@ const getCookie = require('../utils/pypasswaf');
const host = 'http://aao.nuaa.edu.cn/';
const map = new Map([
['tzgg', { title: '南京航空航天大学教务处 -- 通知公告', suffix: '8222/list.htm' }],
['jxfw', { title: '南京航空航天大学教务处 -- 教学服务', suffix: '8230/list.htm' }],
['xspy', { title: '南京航空航天大学教务处 -- 学生培养', suffix: '8231/list.htm' }],
['jxjs', { title: '南京航空航天大学教务处 -- 教学建设', suffix: '8232/list.htm' }],
['jxzy', { title: '南京航空航天大学教务处 -- 教学资源', suffix: '8233/list.htm' }],
['tzgg', { title: '通知公告 | 南京航空航天大学教务处', suffix: '8222/list.htm' }],
['jxfw', { title: '教学服务 | 南京航空航天大学教务处', suffix: '8230/list.htm' }],
['xspy', { title: '学生培养 | 南京航空航天大学教务处', suffix: '8231/list.htm' }],
['jxjs', { title: '教学建设 | 南京航空航天大学教务处', suffix: '8232/list.htm' }],
['jxzy', { title: '教学资源 | 南京航空航天大学教务处', suffix: '8233/list.htm' }],
]);
module.exports = async (ctx) => {
@@ -18,7 +18,7 @@ module.exports = async (ctx) => {
const getDescription = Boolean(ctx.params.getDescription) || false;
const link = new URL(suffix, host).href;
const cookie = await getCookie();
const cookie = await getCookie(host);
const gotConfig = {
headers: {
cookie,
@@ -40,36 +40,30 @@ module.exports = async (ctx) => {
.get();
const out = await Promise.all(
list.map((info) => {
list.map(async (info) => {
const title = info.title || 'tzgg';
const date = info.date;
const itemUrl = new URL(info.link, host).href;
let description = title + '<br><a href="' + itemUrl + '" target="_blank">查看原文</a>';
return ctx.cache.tryGet(itemUrl, async () => {
const arr = itemUrl.split('.');
const pageType = arr[arr.length - 1];
// 南航新 WAF 过于敏感
// 目前 description 需要遍历页面,会被 WAF 拦截导致无法输出
// 考虑换一种获取 description 的方式或者将标题当作 title。
let description = title;
if (getDescription) {
description = itemUrl;
if (getDescription) {
description = await ctx.cache.tryGet(itemUrl, async () => {
const arr = itemUrl.split('.');
const pageType = arr[arr.length - 1];
if (pageType === 'htm' || pageType === 'html') {
const response = await got(itemUrl, gotConfig);
const $ = cheerio.load(response.data);
description = $('.wp_articlecontent').html();
return $('.wp_articlecontent').html() + '<br><hr /><a href="' + itemUrl + '" target="_blank">查看原文</a>';
}
}
});
}
const single = {
title,
link: itemUrl,
description,
pubDate: parseDate(date),
};
return single;
});
return {
title,
link: itemUrl,
description,
pubDate: parseDate(date),
};
})
);
+4 -3
View File
@@ -1,5 +1,6 @@
module.exports = {
'/cs/:type/:getDescription?': ['LogicJake', 'Seiry', 'qrzbing'],
'/jwc/:type/:getDescription?': ['arcosx', 'Seiry', 'qrzbing'],
'/yjsy/:type?': ['junfengP', 'Seiry'],
'/cae/:type/:getDescription?': ['Xm798'],
'/cs/:type/:getDescription?': ['LogicJake', 'Seiry', 'qrzbing', 'Xm798'],
'/jwc/:type/:getDescription?': ['arcosx', 'Seiry', 'qrzbing', 'Xm798'],
'/yjsy/:type/:getDescription?': ['junfengP', 'Seiry', 'Xm798'],
};
+6
View File
@@ -7,6 +7,12 @@ module.exports = {
docs: 'https://docs.rsshub.app/university.html#nan-jing-hang-kong-hang-tian-da-xue',
},
],
cae: [
{
title: '自动化学院',
docs: 'https://docs.rsshub.app/university.html#nan-jing-hang-kong-hang-tian-da-xue',
},
],
cs: [
{
title: '计算机科学与技术学院',
+3 -2
View File
@@ -1,5 +1,6 @@
module.exports = (router) => {
router.get('/cs/:type/:getDescription?', require('./cs/index'));
router.get('/cae/:type/:getDescription?', require('./college/cae'));
router.get('/cs/:type/:getDescription?', require('./college/cs'));
router.get('/jwc/:type/:getDescription?', require('./jwc/jwc'));
router.get('/yjsy/:type?', require('./yjsy/yjsy'));
router.get('/yjsy/:type/:getDescription?', require('./yjsy/yjsy'));
};
+1 -3
View File
@@ -1,10 +1,8 @@
const host = 'http://aao.nuaa.edu.cn/';
/**
* async function 获取cookie
* @desc 返回一个可用的cookie,使用 `got` 发起请求的时候,传入到`options.headers.cookie`即可
*/
module.exports = async function getCookie() {
module.exports = async function getCookie(host) {
const browser = await require('@/utils/puppeteer')({ stealth: true });
const page = await browser.newPage();
await page.setRequestInterception(true);
+60 -41
View File
@@ -1,55 +1,74 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const host = 'http://www.graduate.nuaa.edu.cn/';
const { parseDate } = require('@/utils/parse-date');
const getCookie = require('../utils/pypasswaf');
const host = 'http://www.graduate.nuaa.edu.cn/';
const map = {
latest: '2146/list.htm',
yyxw: 'yyxw/list.htm',
sjwj: 'sjwj/list.htm',
glwj: '2017/list.htm',
xxfw: '2147/list.htm',
};
const load = (link, ctx) =>
ctx.cache.tryGet(link, async () => {
const response = await got(host + link);
const $ = cheerio.load(response.data);
const images = $('img');
for (let k = 0; k < images.length; k++) {
$(images[k]).replaceWith(`<img src="${new URL($(images[k]).attr('src'), host).href}" />`);
}
const description = $('.wp_articlecontent').html();
return { description };
});
const map = new Map([
['tzgg', { title: '通知公告 | 南京航空航天大学研究生院', suffix: '2145/list.htm' }],
['xwdt', { title: '新闻动态 | 南京航空航天大学研究生院', suffix: '13276/list.htm' }],
['xsxx', { title: '学术信息 | 南京航空航天大学研究生院', suffix: '13277/list.htm' }],
['ssfc', { title: '师生风采 | 南京航空航天大学研究生院', suffix: '13278/list.htm' }],
]);
module.exports = async (ctx) => {
const type = ctx.params.type ?? 'latest';
const response = await got({
method: 'get',
url: host + map[type],
});
const type = ctx.params.type;
const suffix = map.get(type).suffix;
const getDescription = Boolean(ctx.params.getDescription) || false;
const link = new URL(suffix, host).href;
const cookie = await getCookie(host);
const gotConfig = {
headers: {
cookie,
},
};
const response = await got(link, gotConfig);
const $ = cheerio.load(response.data);
const list = $('#news_list ul.news_ul > li').slice(0, 10).get();
const process = await Promise.all(
list.map(async (item) => {
const a = $(item).find('a');
const t = $(item).find('span');
const itemUrl = a.attr('href');
const single = {
title: a.text(),
link: new URL(itemUrl, host).href,
pubDate: parseDate(t.text(), 'YYYY-MM-DD'),
const list = $('#wp_news_w6 ul li')
.slice(0, 10)
.map(function () {
const info = {
title: $(this).find('a').text(),
link: $(this).find('a').attr('href'),
date: $(this).find('span').text(),
};
return info;
})
.get();
const out = await Promise.all(
list.map(async (info) => {
const title = info.title || 'tzgg';
const date = info.date;
const itemUrl = new URL(info.link, host).href;
let description = title + '<br><a href="' + itemUrl + '" target="_blank">查看原文</a>';
if (getDescription) {
description = await ctx.cache.tryGet(itemUrl, async () => {
const arr = itemUrl.split('.');
const pageType = arr[arr.length - 1];
if (pageType === 'htm' || pageType === 'html') {
const response = await got(itemUrl, gotConfig);
const $ = cheerio.load(response.data);
return $('.wp_articlecontent').html() + '<br><hr /><a href="' + itemUrl + '" target="_blank">查看原文</a>';
}
});
}
return {
title,
link: itemUrl,
description,
pubDate: parseDate(date),
};
const other = await load(itemUrl, ctx);
return { ...single, ...other };
})
);
ctx.state.data = {
title: '南航研究生院',
link: host,
description: '南航研究生院RSS',
item: process,
title: map.get(type).title,
link,
description: '南京航空航天大学研究生院RSS',
item: out,
};
};
@@ -10,9 +10,7 @@ const queryString = require('query-string');
* @returns {Promise<got.AxiosResponse<{illusts: illust[]}>>}
*/
module.exports = function getBookmarks(user_id, token) {
return got({
method: 'get',
url: 'https://app-api.pixiv.net/v1/user/bookmarks/illust',
return got('https://app-api.pixiv.net/v1/user/bookmarks/illust', {
headers: {
...maskHeader,
Authorization: 'Bearer ' + token,
@@ -8,9 +8,7 @@ const queryString = require('query-string');
* @returns {Promise<got.AxiosResponse<{illusts: illust[]}>>}
*/
module.exports = function getUserIllustFollows(token) {
return got({
method: 'get',
url: 'https://app-api.pixiv.net/v2/illust/follow',
return got('https://app-api.pixiv.net/v2/illust/follow', {
headers: {
...maskHeader,
Authorization: 'Bearer ' + token,
@@ -9,9 +9,7 @@ const queryString = require('query-string');
* @returns {Promise<got.AxiosResponse<{illusts: illust[]}>>}
*/
module.exports = function getIllusts(user_id, token) {
return got({
method: 'get',
url: 'https://app-api.pixiv.net/v1/user/illusts',
return got('https://app-api.pixiv.net/v1/user/illusts', {
headers: {
...maskHeader,
Authorization: 'Bearer ' + token,
@@ -14,9 +14,7 @@ const allowMode = ['day', 'week', 'month', 'day_male', 'day_female', 'week_origi
*/
module.exports = function getRanking(mode, date, token) {
assert(allowMode.includes(mode), 'Mode not allow.');
return got({
method: 'get',
url: 'https://app-api.pixiv.net/v1/illust/ranking',
return got('https://app-api.pixiv.net/v1/illust/ranking', {
headers: {
...maskHeader,
Authorization: 'Bearer ' + token,
@@ -15,9 +15,7 @@ const queryString = require('query-string');
* @returns {Promise<got.AxiosResponse<userDetail>>}
*/
module.exports = function getUserDetail(user_id, token) {
return got({
method: 'get',
url: 'https://app-api.pixiv.net/v1/user/detail',
return got('https://app-api.pixiv.net/v1/user/detail', {
headers: {
...maskHeader,
Authorization: 'Bearer ' + token,
@@ -9,9 +9,7 @@ const queryString = require('query-string');
* @returns {Promise<got.AxiosResponse<{illusts: illust[]}>>}
*/
module.exports = function searchIllust(keyword, token) {
return got({
method: 'get',
url: 'https://app-api.pixiv.net/v1/search/illust',
return got('https://app-api.pixiv.net/v1/search/illust', {
headers: {
...maskHeader,
Authorization: 'Bearer ' + token,
@@ -9,9 +9,7 @@ const queryString = require('query-string');
* @returns {Promise<got.AxiosResponse<{illusts: illust[]}>>}
*/
module.exports = function searchPopularIllust(keyword, token) {
return got({
method: 'get',
url: 'https://app-api.pixiv.net/v1/search/popular-preview/illust',
return got('https://app-api.pixiv.net/v1/search/popular-preview/illust', {
headers: {
...maskHeader,
Authorization: 'Bearer ' + token,
@@ -1,8 +1,9 @@
const getToken = require('./token');
const { getToken } = require('./token');
const getBookmarks = require('./api/getBookmarks');
const getUserDetail = require('./api/getUserDetail');
const config = require('@/config').value;
const pixivUtils = require('./utils');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
if (!config.pixiv || !config.pixiv.refreshToken) {
@@ -11,7 +12,7 @@ module.exports = async (ctx) => {
const id = ctx.params.id;
const token = await getToken();
const token = await getToken(ctx.cache.tryGet);
if (!token) {
throw 'pixiv not login';
}
@@ -30,7 +31,7 @@ module.exports = async (ctx) => {
return {
title: illust.title,
author: illust.user.name,
pubDate: new Date(illust.create_date).toUTCString(),
pubDate: parseDate(illust.create_date),
description: `<p>画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}</p>${images.join('')}`,
link: `https://www.pixiv.net/artworks/${illust.id}`,
};
@@ -1,15 +1,16 @@
const getToken = require('./token');
const { getToken } = require('./token');
const getIllustFollows = require('./api/getIllustFollows');
const config = require('@/config').value;
const pixivUtils = require('./utils');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
if (!config.pixiv || !config.pixiv.refreshToken) {
throw 'pixiv RSS is disabled due to the lack of <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>';
}
const token = await getToken();
if (!(await getToken())) {
const token = await getToken(ctx.cache.tryGet);
if (!token) {
throw 'pixiv not login';
}
@@ -24,7 +25,7 @@ module.exports = async (ctx) => {
return {
title: illust.title,
author: illust.user.name,
pubDate: new Date(illust.create_date).toUTCString(),
pubDate: parseDate(illust.create_date),
description: `<p>画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}</p>${images.join('')}`,
link: `https://www.pixiv.net/artworks/${illust.id}`,
};
+8
View File
@@ -0,0 +1,8 @@
module.exports = {
'/ranking/:mode/:date?': ['EYHN'],
'/search/:keyword/:order?/:mode?': ['DIYgod'],
'/user/bookmarks/:id': ['EYHN'],
'/user/illustfollows': ['ClarkeCheng'],
'/user/novels/:id': ['TonyRL'],
'/user/:id': ['DIYgod'],
};
+35
View File
@@ -0,0 +1,35 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const baseUrl = 'https://www.pixiv.net';
module.exports = async (ctx) => {
const { id } = ctx.params;
const { data } = await got(`${baseUrl}/ajax/user/${id}/profile/all`);
const items = [
...data.body.novelSeries.map((item) => ({
title: item.title,
description: item.caption,
link: `https://www.pixiv.net/novel/series/${item.id}`,
author: item.userName,
pubDate: parseDate(item.createDate),
updated: parseDate(item.updateDate),
category: item.tags,
})),
...data.body.pickup.map((item) => ({
title: item.title,
description: item.description,
link: item.contentUrl,
author: item.userName,
pubDate: parseDate(item.createDate),
updated: parseDate(item.updateDate),
category: item.tags,
})),
];
ctx.state.data = {
title: `${data.body.novelSeries[0].userName || data.body.pickup[0].userName} 的小说`,
link: `${baseUrl}/users/${id}/novels`,
item: items,
};
};
@@ -6,7 +6,7 @@ const pixivConfig = require('@/config').value.pixiv;
async function dohResolve(name, jsonDohEndpoint) {
try {
const response = await got.get(jsonDohEndpoint, {
const response = await got(jsonDohEndpoint, {
searchParams: {
name,
type: 'A',
+43
View File
@@ -0,0 +1,43 @@
module.exports = {
'pixiv.net': {
_name: 'Pixiv',
www: [
{
title: '用户收藏',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/users/:id/bookmarks/artworks',
target: '/pixiv/user/bookmarks/:id',
},
{
title: '用户动态',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/users/:id',
target: '/pixiv/user/:id',
},
{
title: '用户小说',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/users/:id/novels',
target: '/pixiv/user/novels/:id',
},
{
title: '排行榜',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/ranking.php',
target: (params, url) => `/pixiv/ranking/${new URL(url).searchParams.get('mode') || 'daily'}`,
},
{
title: '关键词',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: ['/tags/:keyword', '/tags/:keyword/:type?'],
target: (params, url) => `/pixiv/search/:keyword/${new URL(url).searchParams.get('order')}/${new URL(url).searchParams.get('mode')}`,
},
{
title: '关注的新作品',
docs: 'https://docs.rsshub.app/social-media.html#pixiv',
source: '/bookmark_new_illust.php',
target: '/pixiv/user/illustfollows',
},
],
},
};
@@ -1,7 +1,8 @@
const getToken = require('./token');
const { getToken } = require('./token');
const getRanking = require('./api/getRanking');
const config = require('@/config').value;
const pixivUtils = require('./utils');
const { parseDate } = require('@/utils/parse-date');
const titles = {
day: 'pixiv 日排行',
@@ -56,7 +57,7 @@ module.exports = async (ctx) => {
const mode = alias[ctx.params.mode] ? alias[ctx.params.mode] : ctx.params.mode;
const date = ctx.params.date ? new Date(ctx.params.date) : new Date();
const token = await getToken();
const token = await getToken(ctx.cache.tryGet);
if (!token) {
throw 'pixiv not login';
}
@@ -75,7 +76,7 @@ module.exports = async (ctx) => {
const images = pixivUtils.getImgs(illust);
return {
title: `#${index + 1} ${illust.title}`,
pubDate: new Date(illust.create_date).toUTCString(),
pubDate: parseDate(illust.create_date),
description: `<p>画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}</p><br>${images.join('')}`,
link: `https://www.pixiv.net/artworks/${illust.id}`,
author: illust.user.name,
+8
View File
@@ -0,0 +1,8 @@
module.exports = (router) => {
router.get('/ranking/:mode/:date?', require('./ranking'));
router.get('/search/:keyword/:order?/:mode?', require('./search'));
router.get('/user/bookmarks/:id', require('./bookmarks'));
router.get('/user/illustfollows', require('./illustfollow'));
router.get('/user/novels/:id', require('./novels'));
router.get('/user/:id', require('./user'));
};
@@ -1,8 +1,9 @@
const getToken = require('./token');
const { getToken } = require('./token');
const searchPopularIllust = require('./api/searchPopularIllust');
const searchIllust = require('./api/searchIllust');
const config = require('@/config').value;
const pixivUtils = require('./utils');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
if (!config.pixiv || !config.pixiv.refreshToken) {
@@ -13,7 +14,7 @@ module.exports = async (ctx) => {
const order = ctx.params.order || 'date';
const mode = ctx.params.mode;
const token = await getToken();
const token = await getToken(ctx.cache.tryGet);
if (!token) {
throw 'pixiv not login';
}
@@ -40,7 +41,7 @@ module.exports = async (ctx) => {
return {
title: illust.title,
author: illust.user.name,
pubDate: new Date(illust.create_date).toUTCString(),
pubDate: parseDate(illust.create_date),
description: `<p>画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}</p>${images.join('')}`,
link: `https://www.pixiv.net/artworks/${illust.id}`,
};
+86
View File
@@ -0,0 +1,86 @@
const config = require('@/config').value;
const logger = require('@/utils/logger');
const got = require('./pixiv-got');
const { maskHeader } = require('./constants');
let token = null;
const authorizationInfo = {
client_id: 'MOBrBDS8blbauoSck0ZfDbtuzpyT',
client_secret: 'lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj',
hash_secret: '28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c',
};
const refreshToken = (tryGet) =>
tryGet(
'pixiv:accessToken',
() =>
got
.post('https://oauth.secure.pixiv.net/auth/token', {
form: {
...authorizationInfo,
get_secure_url: 1,
grant_type: 'refresh_token',
refresh_token: config.pixiv.refreshToken,
},
headers: {
...maskHeader,
},
responseType: 'json',
resolveBodyOnly: true,
})
.catch((e) => {
logger.error('Pixiv refresh token failed.');
logger.error(e);
}),
3600,
false
);
async function getToken(tryGet) {
const result = await refreshToken(tryGet);
// let expireTime;
if (result && result.access_token) {
logger.debug('Pixiv refresh token success.');
token = result.access_token;
// expireTime = result.expires_in;
}
// } else {
// expireTime = 30;
// logger.error(`Pixiv refresh token failed, retry in ${expireTime} seconds.`);
// }
// If is package, the mock server should be closed after request, needn't to refresh
// if (!config.isPackage) {
// setTimeout(tickToken, expireTime * 1000);
// }
return token;
}
module.exports = {
getToken,
};
// let tickTokenStarted = false;
// async function startTickToken(tryGet) {
// if (!tickTokenStarted) {
// // 如果tickToken没启动
// tickTokenStarted = true;
// await tickToken(tryGet); // 启动tickToken
// }
// }
// async function waitForToken() {
// while (!token) {
// // eslint-disable-next-line no-await-in-loop
// await new Promise((resolve) => setTimeout(resolve, 0));
// }
// return token;
// }
// module.exports = async (tryGet) => {
// await startTickToken(tryGet);
// return waitForToken();
// };
// module.exports.tickToken = tickToken;
@@ -1,7 +1,8 @@
const getToken = require('./token');
const { getToken } = require('./token');
const getIllusts = require('./api/getIllusts');
const config = require('@/config').value;
const pixivUtils = require('./utils');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
if (!config.pixiv || !config.pixiv.refreshToken) {
@@ -9,7 +10,7 @@ module.exports = async (ctx) => {
}
const id = ctx.params.id;
const token = await getToken();
const token = await getToken(ctx.cache.tryGet);
if (!token) {
throw 'pixiv not login';
}
@@ -28,7 +29,7 @@ module.exports = async (ctx) => {
return {
title: illust.title,
author: username,
pubDate: new Date(illust.create_date).toUTCString(),
pubDate: parseDate(illust.create_date),
description: `<p>画师:${username} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}</p>${images.join('')}`,
link: `https://www.pixiv.net/artworks/${illust.id}`,
};
+41
View File
@@ -0,0 +1,41 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate, parseRelativeDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
const timezone = require('@/utils/timezone');
module.exports = async (ctx) => {
const id = ctx.params.id;
const rootUrl = 'https://my.qidian.com';
const currentUrl = `${rootUrl}/author/${id}/`;
const response = await got(currentUrl);
const $ = cheerio.load(response.data);
const authorName = $('.header-msg h1').contents().first().text().trim();
const items = $('.author-work .author-item')
.toArray()
.map((item) => {
item = $(item);
const messageItem = item.find('.author-item-msg');
const updatedDate = messageItem.find('.author-item-update span').text().replace('·', '').trim();
return {
title: messageItem.find('.author-item-title').text().trim(),
author: authorName,
category: messageItem.find('.author-item-exp a').first().text().trim(),
description: art(path.join(__dirname, 'templates/description.art'), {
description: messageItem.find('.author-item-update a').attr('title'),
image: item.find('a img').attr('src'),
}),
pubDate: timezone(/(今|昨)/.test(updatedDate) ? parseRelativeDate(updatedDate) : parseDate(updatedDate, 'YYYY-MM-DD HH:mm'), +8),
link: messageItem.find('.author-item-update a').attr('href'),
};
});
ctx.state.data = {
title: `${authorName} - 起点中文网`,
description: $('.header-msg-desc').text().trim(),
link: currentUrl,
item: items,
};
};
@@ -1,13 +1,11 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const id = ctx.params.id;
const response = await got({
method: 'get',
url: `https://book.qidian.com/info/${id}#Catalog`,
});
const response = await got(`https://book.qidian.com/info/${id}/#Catalog`);
const $ = cheerio.load(response.data);
const name = $('.book-info>h1>em').text();
@@ -15,10 +13,7 @@ module.exports = async (ctx) => {
const csrfToken = response.headers['set-cookie'].find((s) => s.startsWith('_csrfToken=')).split(';')[0];
const chapters_response = await got({
method: 'get',
url: `https://book.qidian.com/ajax/book/category?${csrfToken}&bookId=${id}`,
});
const chapters_response = await got(`https://book.qidian.com/ajax/book/category?${csrfToken}&bookId=${id}`);
const chapter_item = [];
for (let i = 0; i < chapters_response.data.data.vs.length; i++) {
@@ -27,7 +22,7 @@ module.exports = async (ctx) => {
const chapter = chapters[j];
chapter_item.push({
title: chapter.cN,
pubDate: new Date(chapter.uT).toUTCString(),
pubDate: parseDate(chapter.uT),
link: `https://vipreader.qidian.com/chapter/${id}/${chapter.id}`,
});
}
@@ -7,9 +7,7 @@ module.exports = async (ctx) => {
const url = `https://forum.qidian.com/NewForum/List.aspx?BookId=${id}`;
const forum_response = await got({
method: 'get',
url,
const forum_response = await got(url, {
headers: {
Referer: `https://book.qidian.com/info/${id}`,
},
@@ -13,10 +13,7 @@ module.exports = async (ctx) => {
title = '起点中文网';
}
const response = await got({
method: 'get',
url: link,
});
const response = await got(link);
const $ = cheerio.load(response.data);
const list = $('div.other-rec-wrap li');
@@ -1,5 +1,6 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const parseDate = require('@/utils/date');
module.exports = async (ctx) => {
const type = ctx.params.type;
@@ -13,10 +14,7 @@ module.exports = async (ctx) => {
title = '起点中文网';
}
const response = await got({
method: 'get',
url: link,
});
const response = await got(link);
const $ = cheerio.load(response.data);
const list = $('#limit-list li');
@@ -31,7 +29,7 @@ module.exports = async (ctx) => {
return {
title: item.find('.book-mid-info h4 a').text(),
description: img + rank + update + '<br>' + item.find('p.intro').html(),
pubDate: new Date(item.find('p.update span').text()).toUTCString(),
pubDate: parseDate(item.find('p.update span').text()),
link: 'https:' + item.find('.book-mid-info h4 a').attr('href'),
author: item.find('p.author a.name').text(),
};
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
'/author/:id': ['miles170'],
'/chapter/:id': ['Chingyat'],
'/forum/:id': ['Chingyat'],
'/free/:type?': ['LogicJake'],
'/free-next/:type?': ['LogicJake'],
};
+41
View File
@@ -0,0 +1,41 @@
module.exports = {
'qidian.com': {
_name: '起点',
book: [
{
title: '章节',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/info/:id',
target: '/qidian/chapter/:id',
},
{
title: '讨论区',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/info/:id',
target: '/qidian/forum/:id',
},
],
my: [
{
title: '作者',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/author/:id',
target: '/qidian/author/:id',
},
],
www: [
{
title: '限免',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/free',
target: '/qidian/free',
},
{
title: '女生限免',
docs: 'https://docs.rsshub.app/reading.html#qi-dian',
source: '/mm/free',
target: '/qidian/free/mm',
},
],
},
};
+7
View File
@@ -0,0 +1,7 @@
module.exports = (router) => {
router.get('/author/:id', require('./author'));
router.get('/chapter/:id', require('./chapter'));
router.get('/forum/:id', require('./forum'));
router.get('/free/:type?', require('./free'));
router.get('/free-next/:type?', require('./free-next'));
};
+5
View File
@@ -0,0 +1,5 @@
<p>{{ description }}</p>
{{ if image }}
<img src="{{ image }}">
{{ /if }}
{{ author }}
+85
View File
@@ -0,0 +1,85 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const timezone = require('@/utils/timezone');
const cheerio = require('cheerio');
const { art } = require('@/utils/render');
const path = require('path');
module.exports = async (ctx) => {
const id = ctx.params.id;
const link = `/news/breaknews/1/${id}#breaknews`;
const name = await getLinkName(ctx, link);
const rootUrl = 'https://udn.com';
const response = await got(`${rootUrl}/api/more?page=1&channelId=1&cate_id=${id}&type=breaknews`);
const items = await Promise.all(
response.data.lists.map((item) => {
let link = item.titleLink.indexOf('http://') === 0 || item.titleLink.indexOf('https://') === 0 ? item.titleLink : `${rootUrl}${item.titleLink}`;
const linkUrl = new URL(link);
// cleanup query paramter
linkUrl.query = linkUrl.search = '';
link = linkUrl.toString();
return ctx.cache.tryGet(link, async () => {
let result = await got(link);
// VIP article requires redirection
// e.g. https://udn.com/news/story/7331/6576320
const vip = result.data.match(/<script language=javascript>window\.location\.href="(https?:\/\/[^"]+")/);
if (vip) {
result = await got(vip[1]);
}
const $ = cheerio.load(result.data);
const metadata = $('script[type="application/ld+json"]').eq(0).text().trim();
const data = metadata.startsWith('[') ? JSON.parse(metadata)[0] : JSON.parse(metadata);
// e.g. https://udn.com/news/story/7331/6576320
const content = $('.article-content__editor');
// e.g. https://udn.com/news/story/7240/6576424
const body = $('.article-body__editor');
let description = '';
if (data.image) {
description += art(path.join(__dirname, 'templates/figure.art'), {
src: data.image.contentUrl,
alt: data.image.name,
});
}
if (content.length) {
description += content.html();
} else if (body.length) {
description += body.html();
}
return {
title: item.title,
author: data.author.name,
description,
pubDate: timezone(parseDate(item.time.date, 'YYYY-MM-DD HH:mm'), +8),
category: [data.articleSelection, ...data.keywords.split(',')],
link,
};
});
})
);
ctx.state.data = {
title: `即時${name} - 聯合新聞網`,
link: `${rootUrl}${link}`,
description: 'udn.com 提供即時新聞以及豐富的政治、社會、地方、兩岸、國際、財經、數位、運動、NBA、娛樂、生活、健康、旅遊新聞,以最即時、多元的內容,滿足行動世代的需求',
item: items,
};
};
const getLinkName = async (ctx, link) => {
const url = 'https://udn.com/news/breaknews';
const links = await ctx.cache.tryGet(url, async () => {
const result = await got(url);
const $ = cheerio.load(result.data);
const data = $('.cate-list__subheader a')
.get()
.map((item) => {
item = $(item);
return { [item.attr('href')]: item.text().trim() };
});
return Object.assign({}, ...data);
});
if (link in links) {
return links[link];
}
return '列表';
};
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
'/news/breakingnews/:id': ['miles170'],
};
+13
View File
@@ -0,0 +1,13 @@
module.exports = {
'udn.com': {
_name: '聯合新聞網',
'.': [
{
title: '即時新聞',
docs: 'https://docs.rsshub.app/new-media.html#lian-he-xin-wen-wang-ji-shi-xin-wen',
source: '/news/breaknews/1/:id',
target: '/udn/news/breakingnews/:id',
},
],
},
};
+3
View File
@@ -0,0 +1,3 @@
module.exports = (router) => {
router.get('/news/breakingnews/:id', require('./breaking-news'));
};
+4
View File
@@ -0,0 +1,4 @@
<figure>
<picture><img src={{ src }} alt={{ alt }}></picture>
<figurecaption>{{ alt }}</figurecaption>
</figure>
+1
View File
@@ -31,6 +31,7 @@ module.exports = async (ctx) => {
ctx.state.json = {
title: response.data.title,
link: response.data.feed_url,
image: 'https://mp.weixin.qq.com/favicon.ico',
description: response.data.title,
item: items,
};
+4 -3
View File
@@ -49,12 +49,13 @@
"@vuepress/plugin-pwa": "1.9.7",
"@vuepress/shared-utils": "1.9.7",
"cross-env": "7.0.3",
"eslint": "8.22.0",
"eslint": "8.23.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-yml": "1.1.0",
"fs-extra": "10.1.0",
"jest": "29.0.1",
"meilisearch": "0.27.0",
"mockdate": "3.0.5",
"nock": "13.2.9",
"nodemon": "2.0.19",
@@ -91,7 +92,7 @@
"crypto-js": "4.1.1",
"currency-symbol-map": "5.1.0",
"dayjs": "1.11.5",
"dotenv": "16.0.1",
"dotenv": "16.0.2",
"emailjs-imap-client": "3.1.0",
"entities": "3.0.1",
"etag": "1.8.1",
@@ -124,7 +125,7 @@
"puppeteer-extra": "3.3.4",
"puppeteer-extra-plugin-stealth": "2.11.1",
"query-string": "7.1.1",
"rand-user-agent": "1.0.78",
"rand-user-agent": "1.0.79",
"re2": "1.17.7",
"require-all": "3.0.0",
"rss-parser": "3.12.0",
+55
View File
@@ -0,0 +1,55 @@
const { MeiliSearch } = require('meilisearch');
module.exports = async ({ core }, host, apiKey) => {
const client = new MeiliSearch({
host,
apiKey,
});
core.info('Updating displayed attributes');
core.info(
await client
.index('rsshub')
.updateDisplayedAttributes([
'hierarchy_radio_lvl1',
'hierarchy_radio_lvl2',
'hierarchy_radio_lvl3',
'hierarchy_radio_lvl4',
'hierarchy_radio_lvl5',
'hierarchy_lvl0',
'hierarchy_lvl1',
'hierarchy_lvl2',
'hierarchy_lvl3',
'hierarchy_lvl4',
'hierarchy_lvl5',
'hierarchy_lvl6',
'anchor',
'url',
'content',
])
);
core.info('Updating searchable attributes');
core.info(
await client
.index('rsshub')
.updateSearchableAttributes([
'hierarchy_radio_lvl1',
'hierarchy_radio_lvl2',
'hierarchy_radio_lvl3',
'hierarchy_radio_lvl4',
'hierarchy_radio_lvl5',
'hierarchy_lvl0',
'hierarchy_lvl1',
'hierarchy_lvl2',
'hierarchy_lvl3',
'hierarchy_lvl4',
'hierarchy_lvl5',
'hierarchy_lvl6',
'anchor',
'content',
])
);
core.info('Updating sortable attributes');
core.info(await client.index('rsshub').updateSortableAttributes(['anchor']));
};
+30 -30
View File
@@ -983,14 +983,14 @@
enabled "2.0.x"
kuler "^2.0.0"
"@eslint/eslintrc@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f"
integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==
"@eslint/eslintrc@^1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.1.tgz#de0807bfeffc37b964a7d0400e0c348ce5a2543d"
integrity sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^9.3.2"
espree "^9.4.0"
globals "^13.15.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
@@ -1049,6 +1049,11 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d"
integrity sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==
"@humanwhocodes/module-importer@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
"@humanwhocodes/object-schema@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
@@ -5218,10 +5223,10 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
dotenv@16.0.1:
version "16.0.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d"
integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==
dotenv@16.0.2:
version "16.0.2"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.2.tgz#0b0f8652c016a3858ef795024508cddc4bffc5bf"
integrity sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==
dotenv@^6.2.0:
version "6.2.0"
@@ -5743,14 +5748,15 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint@8.22.0:
version "8.22.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.22.0.tgz#78fcb044196dfa7eef30a9d65944f6f980402c48"
integrity sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==
eslint@8.23.0:
version "8.23.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.23.0.tgz#a184918d288820179c6041bb3ddcc99ce6eea040"
integrity sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==
dependencies:
"@eslint/eslintrc" "^1.3.0"
"@eslint/eslintrc" "^1.3.1"
"@humanwhocodes/config-array" "^0.10.4"
"@humanwhocodes/gitignore-to-minimatch" "^1.0.2"
"@humanwhocodes/module-importer" "^1.0.1"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
@@ -5760,7 +5766,7 @@ eslint@8.22.0:
eslint-scope "^7.1.1"
eslint-utils "^3.0.0"
eslint-visitor-keys "^3.3.0"
espree "^9.3.3"
espree "^9.4.0"
esquery "^1.4.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
@@ -5786,12 +5792,11 @@ eslint@8.22.0:
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
espree@^9.3.2, espree@^9.3.3:
version "9.3.3"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.3.tgz#2dd37c4162bb05f433ad3c1a52ddf8a49dc08e9d"
integrity sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==
espree@^9.4.0:
version "9.4.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a"
integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==
dependencies:
acorn "^8.8.0"
acorn-jsx "^5.3.2"
@@ -9585,7 +9590,7 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
meilisearch@^0.27.0:
meilisearch@0.27.0, meilisearch@^0.27.0:
version "0.27.0"
resolved "https://registry.yarnpkg.com/meilisearch/-/meilisearch-0.27.0.tgz#8bd57ddb77b975f93e054cb977b951c488ece297"
integrity sha512-kZOZFIuSO7c6xRf+Y2/9/h6A9pl0sCl/G44X4KuaSwxGbruOZPhmxbeVEgLHBv4pUFvQ56rNVTA/2d/5GCU1YA==
@@ -11721,10 +11726,10 @@ ramda@^0.26.1:
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
rand-user-agent@1.0.78:
version "1.0.78"
resolved "https://registry.yarnpkg.com/rand-user-agent/-/rand-user-agent-1.0.78.tgz#5472e954b06ab1ef8b7b080ebc0db6fd3a9a142d"
integrity sha512-atAfPjApMtpHK6pz+1zD1NYc8rV4ixqz4UtkYw17LSxKvOaaiLZBeUz6keJuTTNoTUjdYFZXAFBy29WHdvxwAw==
rand-user-agent@1.0.79:
version "1.0.79"
resolved "https://registry.yarnpkg.com/rand-user-agent/-/rand-user-agent-1.0.79.tgz#1472d536fdced3e2e2b64cccafafc20651599d91"
integrity sha512-M/KwE9V2ILytCmKNyg8g/ExrQspUUZcBNFbfryLyJuNcPC/x9IYy+9LEZnSio0a5Rfjv/iHXQYTSEqavL0aZrw==
randexp@0.4.6:
version "0.4.6"
@@ -14043,11 +14048,6 @@ uuid@^8.0.0, uuid@^8.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache@^2.0.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
v8-to-istanbul@^9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4"