36 Commits

Author SHA1 Message Date
imsyy
3343f2b5db 📃 docs: 更新文档 2024-01-02 11:22:38 +08:00
imsyy
2b91f3f32b feat: 新增部分接口 2024-01-02 11:20:50 +08:00
底层用户
fa8fb5a47f Merge pull request #38 from x-dr/master
feat:添加一些接口
2024-01-02 09:37:19 +08:00
x-dr
c0cbb3591b feat: 新增NGA论坛热帖 2023-12-27 19:36:38 +08:00
x-dr
4c54be315f feat: 新增网易云音乐飙升榜 2023-12-27 19:36:00 +08:00
x-dr
71a3621fd8 feat: 新增QQ音乐热歌榜 2023-12-27 19:35:25 +08:00
x-dr
e6a02c667f feat: 新增V2EX热帖 2023-12-27 19:34:50 +08:00
x-dr
07c0f6ed9b feat: 豆瓣小组精选榜单 2023-12-27 19:33:39 +08:00
imsyy
b8c16ad88a feat: 新增 Github Trending 榜单 2023-12-27 10:05:15 +08:00
底层用户
5df634058c Merge pull request #37 from x-dr/master
feat: add GitHub Trending Api
2023-12-27 09:59:26 +08:00
imsyy
029fed603b 🐞 fix: 修复英雄联盟更新公告 2023-12-26 15:58:29 +08:00
x-dr
69fb0640be feat: add GitHub Trending Api 2023-12-24 22:44:42 +08:00
imsyy
a4394588c1 feat: 优化 Docker 大小 2023-12-06 12:25:09 +08:00
imsyy
b90c144a62 feat: 添加 Docker 支持 #34 2023-12-06 11:09:31 +08:00
imsyy
36c40b7870 fix: 去除 winston 2023-12-06 09:38:29 +08:00
imsyy
b0dc506cc6 Merge branch 'master' of github.com:imsyy/DailyHotApi 2023-12-06 09:28:20 +08:00
imsyy
68edae7e74 feat: 添加日志输出 2023-12-06 09:25:26 +08:00
imsyy
d6fcb1628e fix: 修复 Vercel 部署失败 #35 2023-12-06 09:23:12 +08:00
imsyy
9eb76a5f52 feat: 添加日志输出 2023-12-05 16:42:25 +08:00
imsyy
aab54d2190 fix: 修复豆瓣新片榜 2023-12-05 11:48:38 +08:00
imsyy
85567ea638 fix: 修正标题 2023-09-06 14:59:15 +08:00
imsyy
6330914d09 feat: 新增豆瓣新片榜 & add ESLint 2023-09-06 14:48:27 +08:00
底层用户
813e88c993 Merge pull request #17 from MyFaith/master
fix: 修复 it 之家重新获取报错
2023-09-06 14:36:48 +08:00
MyFaith
e9dfcad437 豆瓣新片榜 2023-09-05 19:19:10 +08:00
MyFaith
8d7f394153 修复it之家重新获取报错 2023-09-05 19:04:20 +08:00
imsyy
c42573c37c feat: 新增快手热榜及网易新闻 2023-07-17 17:05:09 +08:00
imsyy
8cffc6c701 feat: 新增接口 & 更新说明 2023-07-12 17:28:48 +08:00
底层用户
e079e2efb5 Merge pull request #11 from wp0403/master
fix: 添加抖音热搜和抖音音乐榜
2023-07-12 17:03:18 +08:00
底层用户
9e9fc713de Update and rename douyin2.js to douyin_new.js 2023-07-12 17:02:46 +08:00
底层用户
4ae8e6cfd8 Update douyin_music.js 2023-07-12 16:58:03 +08:00
底层用户
eaba3db4de Rename douyinMusic.js to douyin_music.js 2023-07-12 16:43:36 +08:00
底层用户
c71e4267ff Update and rename douyinmusic.js to douyinMusic.js 2023-07-12 16:39:23 +08:00
王鹏
30f99cd010 fix: 修改抖音跳转路径 2023-07-12 15:10:29 +08:00
王鹏
87f0ca3c78 fix: 修改抖音移动端url 2023-07-12 11:35:35 +08:00
王鹏
5b63365423 fix: 修改文件名称 2023-07-11 17:26:34 +08:00
王鹏
78e25f8b3a fix: 添加抖音热搜和抖音音乐榜 2023-07-11 17:03:27 +08:00
40 changed files with 2917 additions and 133 deletions

15
.dockerignore Normal file
View File

@@ -0,0 +1,15 @@
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.github
.gitignore
README.md
LICENSE
.vscode
dist
build
images
script

19
.eslintrc.json Normal file
View File

@@ -0,0 +1,19 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended", "plugin:vue/vue3-essential"],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["vue"],
"rules": {},
"globals": {
"require": true,
"module": true,
"process": true,
"__dirname": true
}
}

8
.prettierrc.json Normal file
View File

@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"singleQuote": false,
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"printWidth": 100
}

10
Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 6688
CMD ["npm", "start"]

113
README.md
View File

@@ -14,35 +14,78 @@
> 🟢 状态正常
> 🟠 可能失效
> 🔴 无法使用
> 无法使用
| **站点** | **类别** | **调用名称** | **状态** |
| ------------ | -------- | ------------ | -------- |
| 哔哩哔哩 | 热门榜 | bilibili | 🟢 |
| 知乎 | 热榜 | zhihu | 🟢 |
| 百度 | 热榜 | baidu | 🟢 |
| 百度贴吧 | 热榜 | tieba | 🟢 |
| 少数派 | 热榜 | sspai | 🟢 |
| IT 之家 | 热榜 | ithome | 🟠 |
| 澎湃新闻 | 热榜 | thepaper | 🟢 |
| 今日头条 | 热榜 | toutiao | 🟢 |
| 微博热搜 | 热榜 | weibo | 🟢 |
| 36 氪 | 热榜 | 36kr | 🟢 |
| 稀土掘金 | 热榜 | juejin | 🟢 |
| 腾讯新闻 | 热榜 | newsqq | 🟢 |
| 抖音热榜 | 热榜 | douyin | 🟢 |
| 英雄联盟 | 更新公告 | lol | 🟢 |
| 微信读书 | 飙升榜 | weread | 🟢 |
| 历史上的今天 | 指定日期 | calendar | 🟢 |
| **站点** | **类别** | **调用名称** | **状态** |
| ------------ | -------- | --------------------- | -------- |
| 哔哩哔哩 | 热门榜 | bilibili | 🟢 |
| 微博 | 热榜 | weibo | 🟢 |
| 知乎 | 热榜 | zhihu | 🟢 |
| 百度 | 热榜 | baidu | 🟢 |
| 抖音 | 热榜 | douyin / douyin_new | 🟢 |
| 抖音 | 热榜 | douyin_music | 🟢 |
| 豆瓣 | 新片榜 | douban_new | 🟢 |
| 豆瓣讨论小组 | 讨论精选 | douban_group | 🟢 |
| 百度贴吧 | 热榜 | tieba | 🟢 |
| 少数派 | 热榜 | sspai | 🟢 |
| IT 之家 | 热榜 | ithome | 🟠 |
| 澎湃新闻 | 热榜 | thepaper | 🟢 |
| 今日头条 | 热榜 | toutiao | 🟢 |
| 36 氪 | 热榜 | 36kr | 🟢 |
| 稀土掘金 | 热榜 | juejin | 🟢 |
| 腾讯新闻 | 热点榜 | newsqq | 🟢 |
| 网易新闻 | 热点榜 | netease | 🟢 |
| 英雄联盟 | 更新公告 | lol | 🟢 |
| 原神 | 最新消息 | genshin | 🟢 |
| 微信读书 | 飙升榜 | weread | 🟢 |
| 快手 | 热榜 | kuaishou | 🟢 |
| 网易云音乐 | 排行榜 | netease_music_toplist | 🟢 |
| QQ音乐 | 排行榜 | qq_music_toplist | 🟢 |
| NGA | 热帖 | ngabbs | 🟢 |
| Github | Trending | github | 🟢 |
| V2EX | 热榜 | v2ex | 🟠 |
| 历史上的今天 | 指定日期 | calendar | 🟢 |
### 特殊接口说明
#### 网易云音乐
调用网易云音乐排行榜需要传入指定榜单类别
| 参数名 | 参数值 | 说明 |
| ------ | ------ | ------ |
| type | 1 | 飙升榜 |
| type | 2 | 新歌榜 |
| type | 3 | 原创榜 |
| type | 4 | 热歌榜 |
```http
GET https://example.com/netease_music_toplist?type=1
```
#### QQ音乐
调用QQ音乐排行榜需要传入指定榜单类别
| 参数名 | 参数值 | 说明 |
| ------ | ------ | ---------------- |
| type | 1 | 飙升榜 |
| type | 2 | 热歌榜 |
| type | 3 | 新歌榜 |
| type | 4 | 流行指数榜 |
| type | 5 | 腾讯音乐人原创榜 |
| type | 6 | 听歌识曲榜 |
```http
GET https://example.com/qq_music_toplist?type=1
```
#### 获取全部接口信息
获取除了下方特殊接口外的全部接口列表
```http
GET https://{example.com}/all
GET https://example.com/all
```
#### 历史上的今天(指定日期)
@@ -50,19 +93,41 @@ GET https://{example.com}/all
将指定的月份和日期传入即可得到当天数据,请注意格式
```http
GET https://{example.com}/calendar/date?month=06&day=01
GET https://example.com/calendar/date?month=06&day=01
```
## 部署
```js
// 安装依赖
```bash
# 安装依赖
pnpm install
// 运行
# 运行
pnpm start
```
## Docker 部署
> 安装及配置 Docker 将不在此处说明,请自行解决
### 本地构建
```bash
# 构建
docker build -t dailyhot-api .
# 运行
docker run -p 6688:6688 -d dailyhot-api
```
### 在线部署
```bash
# 拉取
docker pull imsyy/dailyhot-api:latest
# 运行
docker run -p 6688:6688 -d imsyy/dailyhot-api:latest
```
## Vercel 部署
现已支持 Vercel 部署,无需服务器

View File

@@ -24,7 +24,7 @@ app.use(views(__dirname + "/public"));
app.use(
cors({
origin: domain,
})
}),
);
app.use(async (ctx, next) => {
@@ -50,7 +50,7 @@ app.use(router.allowedMethods());
// 启动应用程序并监听端口
const startApp = (port) => {
app.listen(port, () => {
console.log(`成功在 ${port} 端口上运行`);
console.info(`成功在 ${port} 端口上运行`);
});
};
@@ -61,7 +61,7 @@ const checkPort = (port) => {
.createServer()
.once("error", (err) => {
if (err.code === "EADDRINUSE") {
console.log(`端口 ${port} 已被占用, 正在尝试其他端口...`);
console.info(`端口 ${port} 已被占用, 正在尝试其他端口...`);
server.close();
resolve(false);
} else {

View File

@@ -1,11 +1,13 @@
{
"name": "dailyhot_api",
"version": "1.0.0",
"description": "一个今日热榜",
"version": "1.0.7",
"description": "An api on Today's Hot list",
"main": "index.js",
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
"start": "node index.js",
"dev": "./node_modules/.bin/nodemon index.js",
"dev": "npx nodemon index.js",
"prd": "pm2 start index.js",
"build": "node index.js"
},
@@ -15,6 +17,8 @@
"axios": "^1.3.4",
"cheerio": "1.0.0-rc.12",
"dotenv": "^16.0.3",
"eslint": "^8.48.0",
"eslint-plugin-vue": "^9.17.0",
"koa": "^2.14.1",
"koa-bodyparser": "^4.3.0",
"koa-router": "^12.0.0",
@@ -22,6 +26,7 @@
"koa-views": "^8.0.0",
"koa2-cors": "^2.0.6",
"node-cache": "^5.1.2",
"nodemon": "^2.0.22"
"nodemon": "^2.0.22",
"prettier": "^3.0.2"
}
}

663
pnpm-lock.yaml generated
View File

@@ -1,4 +1,4 @@
lockfileVersion: '6.1'
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
@@ -14,6 +14,12 @@ dependencies:
dotenv:
specifier: ^16.0.3
version: 16.0.3
eslint:
specifier: ^8.48.0
version: 8.48.0
eslint-plugin-vue:
specifier: ^9.17.0
version: 9.17.0(eslint@8.48.0)
koa:
specifier: ^2.14.1
version: 2.14.1
@@ -38,9 +44,95 @@ dependencies:
nodemon:
specifier: ^2.0.22
version: 2.0.22
prettier:
specifier: ^3.0.2
version: 3.0.2
packages:
/@aashutoshrathi/word-wrap@1.2.6:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'}
dev: false
/@eslint-community/eslint-utils@4.4.0(eslint@8.48.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
dependencies:
eslint: 8.48.0
eslint-visitor-keys: 3.4.3
dev: false
/@eslint-community/regexpp@4.8.0:
resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
dev: false
/@eslint/eslintrc@2.1.2:
resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
ajv: 6.12.6
debug: 4.3.4
espree: 9.6.1
globals: 13.21.0
ignore: 5.2.4
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
dev: false
/@eslint/js@8.48.0:
resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: false
/@humanwhocodes/config-array@0.11.11:
resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==}
engines: {node: '>=10.10.0'}
dependencies:
'@humanwhocodes/object-schema': 1.2.1
debug: 4.3.4
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
dev: false
/@humanwhocodes/module-importer@1.0.1:
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
dev: false
/@humanwhocodes/object-schema@1.2.1:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
dev: false
/@nodelib/fs.stat@2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
dev: false
/@nodelib/fs.walk@1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
dev: false
/abbrev@1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
dev: false
@@ -53,6 +145,41 @@ packages:
negotiator: 0.6.3
dev: false
/acorn-jsx@5.3.2(acorn@8.10.0):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 8.10.0
dev: false
/acorn@8.10.0:
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: false
/ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies:
fast-deep-equal: 3.1.3
fast-json-stable-stringify: 2.1.0
json-schema-traverse: 0.4.1
uri-js: 4.4.1
dev: false
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: false
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: false
/any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
dev: false
@@ -65,6 +192,10 @@ packages:
picomatch: 2.3.1
dev: false
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: false
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
@@ -136,6 +267,19 @@ packages:
get-intrinsic: 1.2.0
dev: false
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
dev: false
/chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: false
/cheerio-select@2.1.0:
resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
dependencies:
@@ -194,6 +338,17 @@ packages:
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
dev: false
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
@@ -417,6 +572,15 @@ packages:
resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==}
dev: false
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
dev: false
/css-select@5.1.0:
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
dependencies:
@@ -432,6 +596,12 @@ packages:
engines: {node: '>= 6'}
dev: false
/cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
dev: false
/debug@3.2.7(supports-color@5.5.0):
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
@@ -460,6 +630,10 @@ packages:
resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==}
dev: false
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: false
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
@@ -484,6 +658,13 @@ packages:
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
dev: false
/doctrine@3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
dependencies:
esutils: 2.0.3
dev: false
/dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
dependencies:
@@ -544,6 +725,121 @@ packages:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
dev: false
/escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
dev: false
/eslint-plugin-vue@9.17.0(eslint@8.48.0):
resolution: {integrity: sha512-r7Bp79pxQk9I5XDP0k2dpUC7Ots3OSWgvGZNu3BxmKK6Zg7NgVtcOB6OCna5Kb9oQwJPl5hq183WD0SY5tZtIQ==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.2.0 || ^7.0.0 || ^8.0.0
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0)
eslint: 8.48.0
natural-compare: 1.4.0
nth-check: 2.1.1
postcss-selector-parser: 6.0.13
semver: 7.5.4
vue-eslint-parser: 9.3.1(eslint@8.48.0)
xml-name-validator: 4.0.0
transitivePeerDependencies:
- supports-color
dev: false
/eslint-scope@7.2.2:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
dev: false
/eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: false
/eslint@8.48.0:
resolution: {integrity: sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.48.0)
'@eslint-community/regexpp': 4.8.0
'@eslint/eslintrc': 2.1.2
'@eslint/js': 8.48.0
'@humanwhocodes/config-array': 0.11.11
'@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
debug: 4.3.4
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
esquery: 1.5.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
find-up: 5.0.0
glob-parent: 6.0.2
globals: 13.21.0
graphemer: 1.4.0
ignore: 5.2.4
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
js-yaml: 4.1.0
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.3
strip-ansi: 6.0.1
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
dev: false
/espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
acorn: 8.10.0
acorn-jsx: 5.3.2(acorn@8.10.0)
eslint-visitor-keys: 3.4.3
dev: false
/esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'}
dependencies:
estraverse: 5.3.0
dev: false
/esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
dependencies:
estraverse: 5.3.0
dev: false
/estraverse@5.3.0:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
dev: false
/esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
dev: false
/extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
@@ -551,6 +847,31 @@ packages:
is-extendable: 0.1.1
dev: false
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: false
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: false
/fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
dev: false
/fastq@1.15.0:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies:
reusify: 1.0.4
dev: false
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0}
dependencies:
flat-cache: 3.1.0
dev: false
/fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
@@ -558,6 +879,27 @@ packages:
to-regex-range: 5.0.1
dev: false
/find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
dev: false
/flat-cache@3.1.0:
resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==}
engines: {node: '>=12.0.0'}
dependencies:
flatted: 3.2.7
keyv: 4.5.3
rimraf: 3.0.2
dev: false
/flatted@3.2.7:
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
dev: false
/follow-redirects@1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
@@ -620,6 +962,24 @@ packages:
is-glob: 4.0.3
dev: false
/glob-parent@6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
dependencies:
is-glob: 4.0.3
dev: false
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
dev: false
/glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
@@ -631,11 +991,27 @@ packages:
once: 1.4.0
dev: false
/globals@13.21.0:
resolution: {integrity: sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.20.2
dev: false
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
dev: false
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
dev: false
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: false
/has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
@@ -715,6 +1091,24 @@ packages:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
dev: false
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
dev: false
/import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
dev: false
/imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
dev: false
/inflation@2.0.0:
resolution: {integrity: sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==}
engines: {node: '>= 0.8.0'}
@@ -779,11 +1173,20 @@ packages:
engines: {node: '>=0.12.0'}
dev: false
/is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
dev: false
/is-whitespace@0.3.0:
resolution: {integrity: sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==}
engines: {node: '>=0.10.0'}
dev: false
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: false
/js-beautify@1.14.7:
resolution: {integrity: sha512-5SOX1KXPFKx+5f6ZrPsIPEY7NwKeQz47n3jm2i+XeHx9MoRsfQenlOP13FQhWvg8JRS0+XLO6XYUQ2GX+q+T9A==}
engines: {node: '>=10'}
@@ -795,6 +1198,25 @@ packages:
nopt: 6.0.0
dev: false
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
dependencies:
argparse: 2.0.1
dev: false
/json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
dev: false
/json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: false
/json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
dev: false
/keygrip@1.1.0:
resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
engines: {node: '>= 0.6'}
@@ -802,6 +1224,12 @@ packages:
tsscmp: 1.0.6
dev: false
/keyv@4.5.3:
resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==}
dependencies:
json-buffer: 3.0.1
dev: false
/kind-of@3.2.2:
resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
engines: {node: '>=0.10.0'}
@@ -968,6 +1396,29 @@ packages:
- supports-color
dev: false
/levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.2.1
type-check: 0.4.0
dev: false
/locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
dependencies:
p-locate: 5.0.0
dev: false
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: false
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: false
/lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
dependencies:
@@ -975,6 +1426,13 @@ packages:
yallist: 2.1.2
dev: false
/lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
dependencies:
yallist: 4.0.0
dev: false
/media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
@@ -1026,6 +1484,10 @@ packages:
thenify-all: 1.6.0
dev: false
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: false
/negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
@@ -1107,6 +1569,39 @@ packages:
resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==}
dev: false
/optionator@0.9.3:
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
engines: {node: '>= 0.8.0'}
dependencies:
'@aashutoshrathi/word-wrap': 1.2.6
deep-is: 0.1.4
fast-levenshtein: 2.0.6
levn: 0.4.1
prelude-ls: 1.2.1
type-check: 0.4.0
dev: false
/p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
dependencies:
yocto-queue: 0.1.0
dev: false
/p-locate@5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
dependencies:
p-limit: 3.1.0
dev: false
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
dependencies:
callsites: 3.1.0
dev: false
/parse5-htmlparser2-tree-adapter@7.0.0:
resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
dependencies:
@@ -1125,11 +1620,21 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
dev: false
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
dev: false
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
dev: false
/path-to-regexp@6.2.1:
resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
dev: false
@@ -1144,6 +1649,25 @@ packages:
engines: {node: '>=6'}
dev: false
/postcss-selector-parser@6.0.13:
resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==}
engines: {node: '>=4'}
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
dev: false
/prettier@3.0.2:
resolution: {integrity: sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==}
engines: {node: '>=14'}
hasBin: true
dev: false
/pretty@2.0.0:
resolution: {integrity: sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==}
engines: {node: '>=0.10.0'}
@@ -1169,6 +1693,11 @@ packages:
resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
dev: false
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
dev: false
/qs@6.11.0:
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
engines: {node: '>=0.6'}
@@ -1176,6 +1705,10 @@ packages:
side-channel: 1.0.4
dev: false
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: false
/raw-body@2.5.2:
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
engines: {node: '>= 0.8'}
@@ -1193,6 +1726,11 @@ packages:
picomatch: 2.3.1
dev: false
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
dev: false
/resolve-path@1.4.0:
resolution: {integrity: sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==}
engines: {node: '>= 0.8'}
@@ -1201,6 +1739,24 @@ packages:
path-is-absolute: 1.0.1
dev: false
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: false
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
dependencies:
glob: 7.2.3
dev: false
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
dev: false
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
@@ -1219,6 +1775,14 @@ packages:
hasBin: true
dev: false
/semver@7.5.4:
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
lru-cache: 6.0.0
dev: false
/setprototypeof@1.1.0:
resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==}
dev: false
@@ -1227,6 +1791,18 @@ packages:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
dev: false
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
dev: false
/shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
dev: false
/side-channel@1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
@@ -1256,6 +1832,18 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: false
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
dev: false
/supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
@@ -1263,6 +1851,17 @@ packages:
has-flag: 3.0.0
dev: false
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: false
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: false
/thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}
@@ -1300,6 +1899,18 @@ packages:
engines: {node: '>=0.6.x'}
dev: false
/type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.2.1
dev: false
/type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
dev: false
/type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
@@ -1317,20 +1928,70 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.3.0
dev: false
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: false
/vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
dev: false
/vue-eslint-parser@9.3.1(eslint@8.48.0):
resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '>=6.0.0'
dependencies:
debug: 4.3.4
eslint: 8.48.0
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
esquery: 1.5.0
lodash: 4.17.21
semver: 7.5.4
transitivePeerDependencies:
- supports-color
dev: false
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
dev: false
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: false
/xml-name-validator@4.0.0:
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
engines: {node: '>=12'}
dev: false
/yallist@2.1.2:
resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
dev: false
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: false
/ylru@1.3.2:
resolution: {integrity: sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==}
engines: {node: '>= 4.0.0'}
dev: false
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: false

View File

@@ -1,13 +1,9 @@
<!DOCTYPE html>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>404 | Linkbook API</title>
<link
rel="shortcut icon"
href="https://img.imsyy.top/logo/imsyy.png"
type="image/x-icon"
/>
<title>404 | DailyHot API</title>
<link rel="shortcut icon" href="https://img.imsyy.top/logo/imsyy.png" type="image/x-icon" />
<link
rel="stylesheet"
href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/6.0.0/css/all.min.css"
@@ -38,7 +34,9 @@
background-color: var(--text-color-hover);
color: var(--text-color);
font-family: "PingFang SC", "Open Sans", "Microsoft YaHei", sans-serif;
transition: background-color 0.5s, color 0.5s;
transition:
background-color 0.5s,
color 0.5s;
display: flex;
flex-direction: column;
align-items: center;
@@ -149,16 +147,12 @@
<a href="https://imsyy.top/" target="_blank">無名</a>
</div>
<div class="icp">
<a href="https://beian.miit.gov.cn/" target="_blank"
>豫ICP备2022018134号-1</a
>
<a href="https://beian.miit.gov.cn/" target="_blank">豫ICP备2022018134号-1</a>
</div>
</footer>
<script>
// 跟随系统主题
const darkModeMediaQuery = window.matchMedia(
"(prefers-color-scheme: dark)"
);
const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const toggleDarkMode = (darkModeMediaQuery) => {
if (darkModeMediaQuery.matches) {
document.documentElement.classList.add("dark-mode");

View File

@@ -1,13 +1,9 @@
<!DOCTYPE html>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>DailyHot API</title>
<link
rel="shortcut icon"
href="./favicon.svg"
type="image/x-icon"
/>
<link rel="shortcut icon" href="./favicon.svg" type="image/x-icon" />
<link
rel="stylesheet"
href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/6.0.0/css/all.min.css"
@@ -38,7 +34,9 @@
background-color: var(--text-color-hover);
color: var(--text-color);
font-family: "PingFang SC", "Open Sans", "Microsoft YaHei", sans-serif;
transition: background-color 0.5s, color 0.5s;
transition:
background-color 0.5s,
color 0.5s;
display: flex;
flex-direction: column;
align-items: center;
@@ -155,16 +153,12 @@
<a href="https://imsyy.top/" target="_blank">無名</a>
</div>
<div class="icp">
<a href="https://beian.miit.gov.cn/" target="_blank"
>豫ICP备2022018134号-1</a
>
<a href="https://beian.miit.gov.cn/" target="_blank">豫ICP备2022018134号-1</a>
</div>
</footer>
<script>
// 跟随系统主题
const darkModeMediaQuery = window.matchMedia(
"(prefers-color-scheme: dark)"
);
const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const toggleDarkMode = (darkModeMediaQuery) => {
if (darkModeMediaQuery.matches) {
document.documentElement.classList.add("dark-mode");

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "36kr",
title: "36氪",
subtitle: "热榜",
};

View File

@@ -4,7 +4,7 @@ const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = { title: "百度", subtitle: "热搜榜" };
const routerInfo = { name: "baidu", title: "百度", subtitle: "热搜榜" };
// 缓存键名
const cacheKey = "baiduData";
@@ -20,7 +20,7 @@ const getData = (data) => {
if (!data) return [];
const dataList = [];
try {
const pattern = /<\!--s-data:(.*?)-->/s;
const pattern = /<!--s-data:(.*?)-->/s;
const matchResult = data.match(pattern);
const jsonObject = JSON.parse(matchResult[1]).cards[0].content;
jsonObject.forEach((v) => {

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "bilibili",
title: "哔哩哔哩",
subtitle: "热门榜",
};

View File

@@ -1,7 +1,7 @@
const Router = require("koa-router");
const calendarRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
const { get, set } = require("../utils/cacheData");
// 缓存键名
const cacheKey = "calendarData";
@@ -96,7 +96,7 @@ calendarRouter.get("/calendar/date", async (ctx) => {
}
// 从服务器拉取最新数据
const response = await axios.get(
`https://baike.baidu.com/cms/home/eventsOnHistory/${month}.json`
`https://baike.baidu.com/cms/home/eventsOnHistory/${month}.json`,
);
const newData = getData(response.data[month][month + day]);
updateTime = new Date().toISOString();

181
routes/douban_group.js Normal file
View File

@@ -0,0 +1,181 @@
/**
* @author: x-dr
* @date: 2023-12-26
* @customEditors: imsyy
* @lastEditTime: 2024-01-02
*/
const Router = require("koa-router");
const doubanGroupNewRouter = new Router();
const axios = require("axios");
const cheerio = require("cheerio");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "douban_group",
title: "豆瓣讨论小组",
subtitle: "精选",
};
// 缓存键名
const cacheKey = "doubanGroupData";
// 调用时间
let updateTime = new Date().toISOString();
const url = "https://www.douban.com/group/explore";
const headers = {
accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
"cache-control": "max-age=0",
"sec-ch-ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
// "cookie": "bid=lLpb6D1JLuw; douban-fav-remind=1; _pk_id.100001.8cb4=e7d91ae46530fd1d.1680518589.; ll=\"118281\"; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1703602972%2C%22http%3A%2F%2Fnew.xianbao.fun%2F%22%5D; _pk_ses.100001.8cb4=1; ap_v=0,6.0"
};
// 数据处理
const getData = (data) => {
if (!data) return false;
const dataList = [];
const $ = cheerio.load(data);
try {
$(`.channel-item`).each((i, e) => {
// console.log($(e).html());
const item = cheerio.load($(e).html());
const title = item("h3")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const url = item("h3 a").attr("href");
const hot = item('div[class="likes"]')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const desc = item('div[class="block"]')
.text()
.replace(/(^\s*)|(\s*$|\n)/g, "");
const source = item('div[class="source"] a')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
// const excerpt = item('.channel-item-desc').text().replace(/(^\s*)|(\s*$)/g, "")
// console.log(title);
// console.log(url);
dataList.push({
title: title,
desc: desc,
url: url,
mobileUrl: url,
hot: hot,
source: source,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// trending
doubanGroupNewRouter.get("/douban_group", async (ctx) => {
console.log("获取豆瓣讨论小组精选");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新豆瓣讨论小组精选");
// 从服务器拉取数据
const response = await axios.get(url, { headers });
// console.log(response.data);
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 豆瓣新片榜 - 获取最新数据
doubanGroupNewRouter.get("/douban_group/new", async (ctx) => {
console.log("获取豆瓣讨论小组精选 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url, { headers });
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新豆瓣讨论小组精选");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
updateTime,
total: newData.length,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
doubanGroupNewRouter.info = routerInfo;
module.exports = doubanGroupNewRouter;

159
routes/douban_new.js Normal file
View File

@@ -0,0 +1,159 @@
/*
* @author: MyFaith
* @date: 2023-09-06
* @customEditors: imsyy
* @lastEditTime: 2023-09-06
*/
const Router = require("koa-router");
const doubanNewRouter = new Router();
const axios = require("axios");
const cheerio = require("cheerio");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "douban_new",
title: "豆瓣",
subtitle: "新片榜",
};
// 缓存键名
const cacheKey = "doubanNewData";
// 调用时间
let updateTime = new Date().toISOString();
// 调用路径
const url = "https://movie.douban.com/chart/";
const headers = {
"User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
};
// 豆瓣新片榜单特殊处理 - 标题
const replaceTitle = (title, score) => {
return `[★${score}] ` + title.replace(/\n/g, "").replace(/ /g, "").replace(/\//g, " / ").trim();
};
// 数据处理
const getData = (data) => {
if (!data) return false;
const dataList = [];
const $ = cheerio.load(data);
try {
$(".article .item").map((idx, item) => {
const id = $(item).find("a").attr("href").split("/").at(-2) ?? "";
const score = $(item).find(".rating_nums").text() ?? "";
dataList.push({
title: replaceTitle($(item).find("a").text(), score),
desc: $(item).find("p").text(),
score,
comments: $(item).find("span.pl").text().match(/\d+/)?.[0] ?? "",
pic: $(item).find("img").attr("src") ?? "",
url: $(item).find("a").attr("href") ?? "",
mobileUrl: `https://m.douban.com/movie/subject/${id}`,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// 豆瓣新片榜
doubanNewRouter.get("/douban_new", async (ctx) => {
console.log("获取豆瓣新片榜");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取豆瓣新片榜");
// 从服务器拉取数据
const response = await axios.get(url, { headers });
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 豆瓣新片榜 - 获取最新数据
doubanNewRouter.get("/douban_new/new", async (ctx) => {
console.log("获取豆瓣新片榜 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url, { headers });
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新获取豆瓣新片榜");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
updateTime,
total: newData.length,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
doubanNewRouter.info = routerInfo;
module.exports = doubanNewRouter;

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "douyin",
title: "抖音",
subtitle: "热点榜",
};
@@ -21,8 +22,7 @@ const url =
"https://www.douyin.com/aweme/v1/web/hot/search/list/?device_platform=webapp&aid=6383&channel=channel_pc_web&detail_list=1&round_trip_time=50";
// Token 获取路径
const cookisUrl =
"https://www.douyin.com/passport/general/login_guiding_strategy/?aid=6383";
const cookisUrl = "https://www.douyin.com/passport/general/login_guiding_strategy/?aid=6383";
// 数据处理
const getData = (data) => {
@@ -36,9 +36,7 @@ const getData = (data) => {
pic: `${v.word_cover.url_list[0]}`,
hot: Number(v.hot_value),
url: `https://www.douyin.com/hot/${encodeURIComponent(v.sentence_id)}`,
mobileUrl: `https://www.douyin.com/hot/${encodeURIComponent(
v.sentence_id
)}`,
mobileUrl: `https://www.douyin.com/hot/${encodeURIComponent(v.sentence_id)}`,
});
});
return dataList;

155
routes/douyin_music.js Normal file
View File

@@ -0,0 +1,155 @@
/*
* @author: WangPeng
* @date: 2023-07-11 16:41:48
* @customEditors: imsyy
* @lastEditTime: 2023-07-11 16:03:12
*/
const Router = require("koa-router");
const douyinMusicRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "douyin_music",
title: "抖音",
subtitle: "热歌榜",
};
// 缓存键名
const cacheKey = "douyinMusicData";
// 调用时间
let updateTime = new Date().toISOString();
// 调用路径
const url = "https://aweme.snssdk.com/aweme/v1/chart/music/list/";
const HEADERS = {
"user-agent": "okhttp3",
};
const QUERIES = {
device_platform: "android",
version_name: "13.2.0",
version_code: "130200",
aid: "1128",
chart_id: "6853972723954146568",
count: "100",
};
// 数据处理
const getData = (data) => {
if (!data) return [];
try {
return data.map((v) => {
const item = v.music_info;
return {
id: item.id,
title: item.title,
album: item.album,
artist: item.author,
pic: item?.cover_large.url_list[0],
lyric: item.lyric_url,
url: item.play_url.uri,
mobileUrl: item.play_url.uri,
// h5Url: item.matched_song?.h5_url,
};
});
} catch (error) {
console.error("数据处理出错" + error);
return [];
}
};
// 抖音热歌榜
douyinMusicRouter.get("/douyin_music", async (ctx) => {
console.log("获取抖音热歌榜");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取抖音热歌榜");
// 从服务器拉取数据
const response = await axios.get(url, {
headers: HEADERS,
params: QUERIES,
});
data = getData(response.data.music_list);
updateTime = new Date().toISOString();
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 抖音热歌榜 - 获取最新数据
douyinMusicRouter.get("/douyin_music/new", async (ctx) => {
console.log("获取抖音热歌榜 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url, {
headers: HEADERS,
params: QUERIES,
});
const newData = getData(response.data.word_list);
updateTime = new Date().toISOString();
console.log("从服务端重新获取抖音热歌榜");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: newData.length,
updateTime,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
douyinMusicRouter.info = routerInfo;
module.exports = douyinMusicRouter;

149
routes/douyin_new.js Normal file
View File

@@ -0,0 +1,149 @@
/*
* @author: WangPeng
* @date: 2023-07-10 16:56:01
* @customEditors: imsyy
* @lastEditTime: 2023-07-11 16:54:38
*/
const Router = require("koa-router");
const douyinNewRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "douyin",
title: "抖音",
subtitle: "热点榜",
};
// 缓存键名
const cacheKey = "douyinHotNewData";
// 调用时间
let updateTime = new Date().toISOString();
// 调用路径
const url = "https://aweme.snssdk.com/aweme/v1/hot/search/list/";
const HEADERS = {
"user-agent": "okhttp3",
};
const QUERIES = {
device_platform: "android",
version_name: "13.2.0",
version_code: "130200",
aid: "1128",
};
// 数据处理
const getData = (data) => {
if (!data) return [];
try {
const jsonObject = data.data.word_list;
return jsonObject.map((v) => {
return {
title: v.word,
pic: `${v.word_cover.url_list[0]}`,
hot: Number(v.hot_value),
url: `https://www.douyin.com/hot/${encodeURIComponent(v.sentence_id)}`,
mobileUrl: `https://www.douyin.com/hot/${encodeURIComponent(v.sentence_id)}`,
};
});
} catch (error) {
console.error("数据处理出错" + error);
return [];
}
};
// 抖音热点榜
douyinNewRouter.get("/douyin_new", async (ctx) => {
console.log("获取抖音热点榜");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取抖音热点榜");
// 从服务器拉取数据
const response = await axios.get(url, {
headers: HEADERS,
params: QUERIES,
});
data = getData(response.data);
updateTime = new Date().toISOString();
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 抖音热点榜 - 获取最新数据
douyinNewRouter.get("/douyin_new/new", async (ctx) => {
console.log("获取抖音热点榜 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url, {
headers: HEADERS,
params: QUERIES,
});
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新获取抖音热点榜");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: newData.length,
updateTime,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
douyinNewRouter.info = routerInfo;
module.exports = douyinNewRouter;

123
routes/genshin.js Normal file
View File

@@ -0,0 +1,123 @@
const Router = require("koa-router");
const genshinRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "genshin",
title: "原神",
subtitle: "最新信息",
};
// 缓存键名
const cacheKey = "genshinData";
// 调用时间
let updateTime = new Date().toISOString();
// 调用路径
const url =
"https://content-static.mihoyo.com/content/ysCn/getContentList?pageSize=50&pageNum=1&channelId=10";
// 数据处理
const getData = (data) => {
if (!data) return [];
return data.map((v) => {
return {
id: v.id,
title: v.title,
pic: v.ext[1]?.value[0]?.url,
start_time: v?.start_time,
url: `https://ys.mihoyo.com/main/news/detail/${v.id}`,
mobileUrl: `https://ys.mihoyo.com/main/m/news/detail/${v.id}`,
};
});
};
// 原神最新信息
genshinRouter.get("/genshin", async (ctx) => {
console.log("获取原神最新信息");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取原神最新信息");
// 从服务器拉取数据
const response = await axios.get(url);
data = getData(response.data.data.list);
updateTime = new Date().toISOString();
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 原神最新信息 - 获取最新数据
genshinRouter.get("/genshin/new", async (ctx) => {
console.log("获取原神最新信息 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url);
const newData = getData(response.data.data.list);
updateTime = new Date().toISOString();
console.log("从服务端重新获取原神最新信息");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: newData.length,
updateTime,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
genshinRouter.info = routerInfo;
module.exports = genshinRouter;

174
routes/github.js Normal file
View File

@@ -0,0 +1,174 @@
/*
* @author: x-dr
* @date: 2023-12-25
* @customEditors: imsyy
* @lastEditTime: 2023-12-27
*/
const Router = require("koa-router");
const githubNewRouter = new Router();
const axios = require("axios");
const cheerio = require("cheerio");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "github",
title: "Github",
subtitle: "trending",
};
// 缓存键名
const cacheKey = "githubData";
// 调用时间
let updateTime = new Date().toISOString();
const url = "https://github.com/trending";
const headers = {
"User-Agent":
"Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
};
// 数据处理
const getData = (data) => {
if (!data) return false;
const dataList = [];
const $ = cheerio.load(data);
try {
$(`.Box-row`).each((i, e) => {
// console.log(getCheerio(e).html());
const item = cheerio.load($(e).html());
// console.log(item);
const title = item("h2 a").attr("href").replace("/", "");
const url = `https://github.com/${title}`;
const excerpt = item("p")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const language = item('.f6 span[itemprop="programmingLanguage"]')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const stars = item(".f6 a:first")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const forks = item(".f6 a:eq(1)")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const starstoday = item(".f6 span:eq(4)")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
dataList.push({
title: title,
desc: excerpt,
url: url,
language: language,
stars: stars,
forks: forks,
starstoday: starstoday,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// trending
githubNewRouter.get("/github", async (ctx) => {
console.log("获取github trending");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新github trending");
// 从服务器拉取数据
const response = await axios.get(url, { headers });
// console.log(response.data);
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// trending - 获取最新数据
githubNewRouter.get("/github/new", async (ctx) => {
console.log("获取github trending - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url, { headers });
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新github trending");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
updateTime,
total: newData.length,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
githubNewRouter.info = routerInfo;
module.exports = githubNewRouter;

View File

@@ -6,6 +6,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "ithome",
title: "IT之家",
subtitle: "热榜",
};
@@ -35,14 +36,13 @@ const getData = (data) => {
const dataList = [];
const $ = cheerio.load(data);
try {
$(".rank-name").each(function () {
$(".rank-name").each(() => {
const type = $(this).data("rank-type");
const newListHtml = $(this).next(".rank-box").html();
cheerio
.load(newListHtml)(".placeholder")
.get()
.map((v) => {
console.log($(v));
dataList.push({
title: $(v).find(".plc-title").text(),
img: $(v).find("img").attr("data-original"),
@@ -127,7 +127,7 @@ itHomeRouter.get("/ithome/new", async (ctx) => {
message: "获取成功",
...routerInfo,
updateTime,
total: data.length,
total: newData.length,
data: newData,
};
@@ -144,7 +144,7 @@ itHomeRouter.get("/ithome/new", async (ctx) => {
code: 200,
message: "获取成功",
...routerInfo,
total: data.length,
total: cachedData.length,
updateTime,
data: cachedData,
};

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "juejin",
title: "稀土掘金",
subtitle: "热榜",
};
@@ -16,8 +17,7 @@ const cacheKey = "juejinData";
let updateTime = new Date().toISOString();
// 调用路径
const url =
"https://api.juejin.cn/content_api/v1/content/article_rank?category_id=1&type=hot";
const url = "https://api.juejin.cn/content_api/v1/content/article_rank?category_id=1&type=hot";
// 数据处理
const getData = (data) => {

162
routes/kuaishou.js Normal file
View File

@@ -0,0 +1,162 @@
/*
* @author: MCBBC
* @date: 2023-07-17
* @customEditors: imsyy
* @lastEditTime: 2023-07-17
*/
const Router = require("koa-router");
const kuaishouRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "kuaishou",
title: "快手",
subtitle: "热榜",
};
// 缓存键名
const cacheKey = "kuaishouData";
// 调用时间
let updateTime = new Date().toISOString();
// 调用路径
const url = "https://www.kuaishou.com/?isHome=1";
// Unicode 解码
const decodedString = (encodedString) => {
return encodedString.replace(/\\u([\d\w]{4})/gi, (match, grp) =>
String.fromCharCode(parseInt(grp, 16)),
);
};
// 数据处理
const getData = (data) => {
if (!data) return [];
const dataList = [];
try {
const pattern = /window.__APOLLO_STATE__=(.*);\(function\(\)/s;
const idPattern = /clientCacheKey=([A-Za-z0-9]+)/s;
const matchResult = data.match(pattern);
const jsonObject = JSON.parse(matchResult[1])["defaultClient"];
// 获取所有分类
const allItems = jsonObject['$ROOT_QUERY.visionHotRank({"page":"home"})']["items"];
// 遍历所有分类
allItems.forEach((v) => {
// 基础数据
const image = jsonObject[v.id]["poster"];
const id = image.match(idPattern)[1];
// 数据处理
dataList.push({
title: jsonObject[v.id]["name"],
pic: decodedString(image),
hot: jsonObject[v.id]["hotValue"],
url: `https://www.kuaishou.com/short-video/${id}`,
mobileUrl: `https://www.kuaishou.com/short-video/${id}`,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// 快手热榜
kuaishouRouter.get("/kuaishou", async (ctx) => {
console.log("获取快手热榜");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取快手热榜");
// 从服务器拉取数据
const response = await axios.get(url);
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 快手热榜 - 获取最新数据
kuaishouRouter.get("/kuaishou/new", async (ctx) => {
console.log("获取快手热榜 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url);
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新获取快手热榜");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: newData.length,
updateTime,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
kuaishouRouter.info = routerInfo;
module.exports = kuaishouRouter;

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "lol",
title: "英雄联盟",
subtitle: "更新公告",
};
@@ -17,28 +18,23 @@ let updateTime = new Date().toISOString();
// 调用路径
const url =
"https://apps.game.qq.com/cmc/zmMcnTargetContentList?r0=jsonp&page=1&num=16&target=24&source=web_pc&r1=jQuery191002324053053181463_1687855508930&_=1687855508933";
"https://apps.game.qq.com/cmc/zmMcnTargetContentList?r0=jsonp&page=1&num=16&target=24&source=web_pc";
// 数据处理
const getData = (data) => {
if (!data) return [];
const dataList = [];
try {
const pattern = /jQuery191002324053053181463_1687855508930\((.*?)\)/s;
const matchResult = data.match(pattern);
const jsonObject = JSON.parse(matchResult[1])["data"].result;
const match = data.match(/callback\((.*)\)/);
const jsonObject = JSON.parse(match[1]).data.result;
jsonObject.forEach((v) => {
dataList.push({
title: v.sTitle,
desc: v.sAuthor,
pic: `https:${v.sIMG}`,
hot: Number(v.iTotalPlay),
url: `https://lol.qq.com/news/detail.shtml?docid=${encodeURIComponent(
v.iDocID
)}`,
mobileUrl: `https://lol.qq.com/news/detail.shtml?docid=${encodeURIComponent(
v.iDocID
)}`,
url: `https://lol.qq.com/news/detail.shtml?docid=${encodeURIComponent(v.iDocID)}`,
mobileUrl: `https://lol.qq.com/news/detail.shtml?docid=${encodeURIComponent(v.iDocID)}`,
});
});
return dataList;

130
routes/netease.js Normal file
View File

@@ -0,0 +1,130 @@
/*
* @author: MCBBC
* @date: 2023-07-17
* @customEditors: imsyy
* @lastEditTime: 2023-07-17
*/
const Router = require("koa-router");
const neteaseRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "netease",
title: "网易新闻",
subtitle: "热点榜",
};
// 缓存键名
const cacheKey = "neteaseData";
// 调用时间
let updateTime = new Date().toISOString();
// 调用路径
const url = "https://m.163.com/fe/api/hot/news/flow";
// 数据处理
const getData = (data) => {
if (!data) return [];
return data.map((v) => {
return {
id: v.skipID,
title: v.title,
desc: v._keyword,
pic: v.imgsrc,
owner: v.source,
url: `https://www.163.com/dy/article/${v.skipID}.html`,
mobileUrl: v.url,
};
});
};
// 网易新闻热榜
neteaseRouter.get("/netease", async (ctx) => {
console.log("获取网易新闻热榜");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取网易新闻热榜");
// 从服务器拉取数据
const response = await axios.get(url);
data = getData(response.data.data.list);
updateTime = new Date().toISOString();
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 网易新闻热榜 - 获取最新数据
neteaseRouter.get("/netease/new", async (ctx) => {
console.log("获取网易新闻热榜 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url);
const newData = getData(response.data.data.list);
updateTime = new Date().toISOString();
console.log("从服务端重新获取网易新闻热榜");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: newData.length,
updateTime,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
neteaseRouter.info = routerInfo;
module.exports = neteaseRouter;

View File

@@ -0,0 +1,198 @@
/**
* @author: x-dr
* @date: 2023-12-27
* @customEditors: imsyy
* @lastEditTime: 2024-01-02
*/
const URL = require("url");
const Router = require("koa-router");
const neteaseMusicRouter = new Router();
const axios = require("axios");
const cheerio = require("cheerio");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "netease_music_toplist",
title: "网易云音乐",
subtitle: "排行榜",
};
// 缓存键名
const cacheKey = "neteasemusicToplistData";
// 调用时间
let updateTime = new Date().toISOString();
const url = "https://music.163.com/discover/toplist?id=";
const headers = {
authority: "music.163.com",
referer: "https://music.163.com/",
};
// 榜单类别
const listType = {
1: {
id: 19723756,
name: "飙升榜",
},
2: {
id: 3779629,
name: "新歌榜",
},
3: {
id: 2884035,
name: "原创榜",
},
4: {
id: 3778678,
name: "热歌榜",
},
};
// 数据处理
const getData = (data) => {
if (!data) return false;
const dataList = [];
const $ = cheerio.load(data);
try {
$(".m-sgitem").each((i, e) => {
const urlString = $(e).attr("href");
const parsedUrl = URL.parse(urlString, true);
const urlidValue = parsedUrl.query.id;
const item = cheerio.load($(e).html());
const author = item('div[class="f-thide sginfo"]')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const title = item('div[class="f-thide sgtl"]')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
dataList.push({
title: title,
desc: author,
url: `https://music.163.com/#/song?id=${urlidValue}`,
mobileUrl: `https://music.163.com/m/song?id=${urlidValue}`,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// 网易云音乐排行榜
neteaseMusicRouter.get("/netease_music_toplist", async (ctx) => {
console.log("获取网易云音乐排行榜");
try {
// 获取参数
const { type } = ctx.query;
const typeNum = Number(type);
if (!typeNum || typeNum > 4 || typeNum < 1) {
ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" };
return false;
}
// 更改名称
routerInfo.subtitle = listType[typeNum].name;
// 从缓存中获取数据
let data = await get(cacheKey + listType[typeNum].id);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取网易云音乐排行榜");
// 从服务器拉取数据
const response = await axios.get(url + listType[typeNum].id, { headers });
// console.log(response.data);
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey + listType[typeNum].id, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 网易云音乐排行榜 - 获取最新数据
neteaseMusicRouter.get("/netease_music_toplist/new", async (ctx) => {
console.log("获取网易云音乐排行榜 - 最新数据");
try {
// 获取参数
const { type } = ctx.query;
const typeNum = Number(type);
if (!typeNum || typeNum > 4 || typeNum < 1) {
ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" };
return false;
}
// 更改名称
routerInfo.subtitle = listType[typeNum].name;
// 从服务器拉取最新数据
const response = await axios.get(url + listType[typeNum].id, { headers });
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新获取网易云音乐排行榜");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
updateTime,
total: newData.length,
data: newData,
};
// 删除旧数据
await del(cacheKey + listType[typeNum].id);
// 将最新数据写入缓存
await set(cacheKey + listType[typeNum].id, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
neteaseMusicRouter.info = routerInfo;
module.exports = neteaseMusicRouter;

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "newsqq",
title: "腾讯新闻",
subtitle: "热点榜",
};

155
routes/ngabbs.js Normal file
View File

@@ -0,0 +1,155 @@
/**
* @author: x-dr
* @date: 2023-12-25
* @customEditors: imsyy
* @lastEditTime: 2024-01-02
*/
const Router = require("koa-router");
const ngabbsRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = { name: "ngabbs", title: "NGA", subtitle: "论坛热帖" };
// 缓存键名
const cacheKey = "ngabbsData";
// 调用时间
let updateTime = new Date().toISOString();
const url =
"https://ngabbs.com/nuke.php?__lib=load_topic&__act=load_topic_reply_ladder2&opt=1&all=1";
const headers = {
Host: "ngabbs.com",
"Content-Type": "application/x-www-form-urlencoded",
Accept: "*/*",
"Accept-Encoding": "gzip, deflate, br",
Connection: "keep-alive",
"Content-Length": "11",
"User-Agent": "NGA/7.3.1 (iPhone; iOS 17.2.1; Scale/3.00)",
"Accept-Language": "zh-Hans-CN;q=1",
Referer: "https://ngabbs.com/",
"X-User-Agent": "NGA_skull/7.3.1(iPhone13,2;iOS 17.2.1)",
};
const postData = { __output: "14" };
// 数据处理
const getData = (data) => {
if (!data) return [];
const dataList = [];
try {
const result = data.result[0];
result.forEach((result) => {
dataList.push({
author: result.author,
desc: result.subject,
parent: result.parent["2"],
tid: result.tid,
comments: Number(result.replies),
url: `https://bbs.nga.cn/read.php?tid=${result.tid}`,
mobileUrl: `https://bbs.nga.cn/read.php?tid=${result.tid}`,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// NGA论坛热帖
ngabbsRouter.get("/ngabbs", async (ctx) => {
console.log("获取NGA论坛热帖");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取NGA论坛热帖");
// 从服务器拉取数据
const response = await axios.post(url, postData, { headers });
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
message: "获取失败",
};
}
});
// NGA论坛热帖 - 获取最新数据
ngabbsRouter.get("/ngabbs/new", async (ctx) => {
console.log("获取NGA论坛热帖 - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.post(url, postData, { headers });
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新获取NGA论坛热帖");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: newData.length,
updateTime,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
ngabbsRouter.info = routerInfo;
module.exports = ngabbsRouter;

211
routes/qq_music_toplist.js Normal file
View File

@@ -0,0 +1,211 @@
/**
* @author: x-dr
* @date: 2023-12-27
* @customEditors: imsyy
* @lastEditTime: 2024-01-02
*/
// const fs = require("fs");
const Router = require("koa-router");
const qqMusicRouter = new Router();
const axios = require("axios");
const cheerio = require("cheerio");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "qq_music_toplist",
title: "QQ音乐",
subtitle: "排行榜",
};
// 缓存键名
const cacheKey = "qqmusicData";
// 调用时间
let updateTime = new Date().toISOString();
const url = "https://y.qq.com/n/ryqq/toplist/";
const headers = {
authority: "y.qq.com",
referer: "https://www.google.com/",
"user-agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
};
// 榜单类别
const listType = {
1: {
id: 62,
name: "飙升榜",
},
2: {
id: 26,
name: "热歌榜",
},
3: {
id: 27,
name: "新歌榜",
},
4: {
id: 4,
name: "流行指数榜",
},
5: {
id: 52,
name: "腾讯音乐人原创榜",
},
6: {
id: 67,
name: "听歌识曲榜",
},
};
// 数据处理
const getData = (data) => {
if (!data) return false;
const dataList = [];
const $ = cheerio.load(data);
// fs.writeFileSync('qq.html', $.html());
try {
$(".songlist__item").each((i, e) => {
const item = cheerio.load($(e).html());
const title = item('a[class="songlist__cover"]').attr("title");
const urlPath = item('a[class="songlist__cover"]').attr("href");
const author = item('div[class="songlist__artist"]')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const songtime = item('div[class="songlist__time"]')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
// const title = item('div[class="f-thide sgtl"]').text().replace(/(^\s*)|(\s*$)/g, "")
dataList.push({
title: title,
desc: author,
songtime: songtime,
url: `https://y.qq.com${urlPath}`,
mobileUrl: `https://y.qq.com${urlPath}`,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// 获取QQ音乐排行榜
qqMusicRouter.get("/qq_music_toplist", async (ctx) => {
console.log("获取QQ音乐排行榜");
try {
// 获取参数
const { type } = ctx.query;
const typeNum = Number(type);
if (!typeNum || typeNum > 6 || typeNum < 1) {
ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" };
return false;
}
// 更改名称
routerInfo.subtitle = listType[typeNum].name;
// 从缓存中获取数据
let data = await get(cacheKey + listType[typeNum].id);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新QQ音乐排行榜");
// 从服务器拉取数据
const response = await axios.get(url + listType[typeNum].id, { headers });
// console.log(response.data);
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey + listType[typeNum].id, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// 获取QQ音乐排行榜 - 获取最新数据
qqMusicRouter.get("/qq_music_toplist/new", async (ctx) => {
console.log("获取QQ音乐排行榜 - 最新数据");
try {
// 获取参数
const { type } = ctx.query;
const typeNum = Number(type);
if (!typeNum || typeNum > 4 || typeNum < 1) {
ctx.body = { code: 400, ...routerInfo, message: "参数不完整或不正确" };
return false;
}
// 更改名称
routerInfo.subtitle = listType[typeNum].name;
// 从服务器拉取最新数据
const response = await axios.get(url + listType[typeNum].id, { headers });
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新QQ音乐排行榜");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
updateTime,
total: newData.length,
data: newData,
};
// 删除旧数据
await del(cacheKey + listType[typeNum].id);
// 将最新数据写入缓存
await set(cacheKey + listType[typeNum].id, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
qqMusicRouter.info = routerInfo;
module.exports = qqMusicRouter;

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "sspai",
title: "少数派",
subtitle: "热榜",
};

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "thepaper",
title: "澎湃新闻",
subtitle: "热榜",
};

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "tieba",
title: "百度贴吧",
subtitle: "热议榜",
};

View File

@@ -5,6 +5,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "toutiao",
title: "今日头条",
subtitle: "热榜",
};

175
routes/v2ex.js Normal file
View File

@@ -0,0 +1,175 @@
/**
* @author: x-dr
* @date: 2023-12-25
* @customEditors: imsyy
* @lastEditTime: 2024-01-02
*/
const Router = require("koa-router");
const v2exRouter = new Router();
const axios = require("axios");
const cheerio = require("cheerio");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "v2ex",
title: "V2EX",
subtitle: "hot",
};
// 缓存键名
const cacheKey = "v2exData";
// 调用时间
let updateTime = new Date().toISOString();
const url = "https://www.v2ex.com/?tab=hot";
const headers = {
"Content-Type": "application/json",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
authority: "www.v2ex.com",
referer: "https://www.v2ex.com/",
};
// 数据处理
const getData = (data) => {
if (!data) return false;
const dataList = [];
const $ = cheerio.load(data);
try {
$(`div[class="cell item"]`).each((i, e) => {
const item = cheerio.load($(e).html());
const title = item('span[class="item_title"]')
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const href = item(".item_title a").attr("href");
const url = `https://www.v2ex.com${href}`;
const comments = item(".count_livid")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const member = item(".topic_info strong a:first")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const node = item(".topic_info .node")
.text()
.replace(/(^\s*)|(\s*$)/g, "");
const avatar_img = item(".avatar").attr("src");
// console.log( url);
dataList.push({
title: title,
url: url,
mobileUrl: url,
comments: comments,
member: member,
node: node,
avatar: avatar_img,
});
});
return dataList;
} catch (error) {
console.error("数据处理出错" + error);
return false;
}
};
// v2ex
v2exRouter.get("/v2ex", async (ctx) => {
console.log("获取v2ex");
try {
// 从缓存中获取数据
let data = await get(cacheKey);
const from = data ? "cache" : "server";
if (!data) {
// 如果缓存中不存在数据
console.log("从服务端重新获取v2ex");
// 从服务器拉取数据
const response = await axios.get(url, { headers });
// console.log(response.data);
data = getData(response.data);
updateTime = new Date().toISOString();
if (!data) {
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
return false;
}
// 将数据写入缓存
await set(cacheKey, data);
}
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
from,
total: data.length,
updateTime,
data,
};
} catch (error) {
console.error(error);
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
});
// v2ex - 获取最新数据
v2exRouter.get("/v2ex/new", async (ctx) => {
console.log("获取v2ex - 最新数据");
try {
// 从服务器拉取最新数据
const response = await axios.get(url, { headers });
const newData = getData(response.data);
updateTime = new Date().toISOString();
console.log("从服务端重新获取v2ex");
// 返回最新数据
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
updateTime,
total: newData.length,
data: newData,
};
// 删除旧数据
await del(cacheKey);
// 将最新数据写入缓存
await set(cacheKey, newData);
} catch (error) {
// 如果拉取最新数据失败,尝试从缓存中获取数据
console.error(error);
const cachedData = await get(cacheKey);
if (cachedData) {
ctx.body = {
code: 200,
message: "获取成功",
...routerInfo,
total: cachedData.length,
updateTime,
data: cachedData,
};
} else {
// 如果缓存中也没有数据,则返回错误信息
ctx.body = {
code: 500,
...routerInfo,
message: "获取失败",
};
}
}
});
v2exRouter.info = routerInfo;
module.exports = v2exRouter;

View File

@@ -6,6 +6,7 @@ const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "weibo",
title: "微博",
subtitle: "热搜榜",
};
@@ -29,11 +30,9 @@ const getData = (data) => {
title: v.word,
desc: key,
hot: v.raw_hot,
url: `https://s.weibo.com/weibo?q=${encodeURIComponent(
key
)}&t=31&band_rank=1&Refer=top`,
url: `https://s.weibo.com/weibo?q=${encodeURIComponent(key)}&t=31&band_rank=1&Refer=top`,
mobileUrl: `https://s.weibo.com/weibo?q=${encodeURIComponent(
key
key,
)}&t=31&band_rank=1&Refer=top`,
};
});

View File

@@ -1,10 +1,12 @@
const Router = require("koa-router");
const wereadRouter = new Router();
const axios = require("axios");
const getWereadID = require("../utils/getWereadID");
const { get, set, del } = require("../utils/cacheData");
// 接口信息
const routerInfo = {
name: "weread",
title: "微信读书",
subtitle: "飙升榜",
};
@@ -23,7 +25,6 @@ const getData = (data) => {
if (!data) return [];
return data.map((v) => {
const book = v.bookInfo;
console.log(book);
return {
id: book.bookId,
title: book.title,
@@ -31,8 +32,8 @@ const getData = (data) => {
pic: book.cover.replace("s_", "t9_"),
hot: v.readingCount,
author: book.author,
url: "https://weread.qq.com/web/category/rising",
mobileUrl: "https://weread.qq.com/web/category/rising",
url: `https://weread.qq.com/web/bookDetail/${getWereadID(book.bookId)}`,
mobileUrl: `https://weread.qq.com/web/bookDetail/${getWereadID(book.bookId)}`,
};
});
};

View File

@@ -2,7 +2,6 @@ const Router = require("koa-router");
const zhihuRouter = new Router();
const axios = require("axios");
const { get, set, del } = require("../utils/cacheData");
const router = require(".");
// 接口信息
const routerInfo = {
@@ -28,8 +27,7 @@ const getData = (data) => {
if (!data) return [];
const dataList = [];
try {
const pattern =
/<script id="js-initialData" type="text\/json">(.*?)<\/script>/;
const pattern = /<script id="js-initialData" type="text\/json">(.*?)<\/script>/;
const matchResult = data.match(pattern);
const jsonObject = JSON.parse(matchResult[1]).initialState.topstory.hotList;
jsonObject.forEach((v) => {

81
utils/getWereadID.js Normal file
View File

@@ -0,0 +1,81 @@
const crypto = require("crypto");
/**
* 获取微信读书的书籍 ID
* 感谢 @MCBBC 及 ChatGPT
* @param {string} bookId - 书籍 ID
* @returns {string} - 唯一的书籍 ID
*/
const getWereadID = (bookId) => {
try {
// 使用 MD5 哈希算法创建哈希对象
const hash = crypto.createHash("md5");
hash.update(bookId);
const str = hash.digest("hex");
// 取哈希结果的前三个字符作为初始值
let strSub = str.substring(0, 3);
// 判断书籍 ID 的类型并进行转换
let fa;
if (/^\d*$/.test(bookId)) {
// 如果书籍 ID 只包含数字,则将其拆分成长度为 9 的子字符串,并转换为十六进制表示
const chunks = [];
for (let i = 0; i < bookId.length; i += 9) {
const chunk = bookId.substring(i, i + 9);
chunks.push(parseInt(chunk).toString(16));
}
fa = ["3", chunks];
} else {
// 如果书籍 ID 包含其他字符,则将每个字符的 Unicode 编码转换为十六进制表示
let hexStr = "";
for (let i = 0; i < bookId.length; i++) {
hexStr += bookId.charCodeAt(i).toString(16);
}
fa = ["4", [hexStr]];
}
// 将类型添加到初始值中
strSub += fa[0];
// 将数字2和哈希结果的后两个字符添加到初始值中
strSub += "2" + str.substring(str.length - 2);
// 处理转换后的子字符串数组
for (let i = 0; i < fa[1].length; i++) {
const sub = fa[1][i];
const subLength = sub.length.toString(16);
// 如果长度只有一位数则在前面添加0
const subLengthPadded = subLength.length === 1 ? "0" + subLength : subLength;
// 将长度和子字符串添加到初始值中
strSub += subLengthPadded + sub;
// 如果不是最后一个子字符串,则添加分隔符 'g'
if (i < fa[1].length - 1) {
strSub += "g";
}
}
// 如果初始值长度不足 20从哈希结果中取足够的字符补齐
if (strSub.length < 20) {
strSub += str.substring(0, 20 - strSub.length);
}
// 使用 MD5 哈希算法创建新的哈希对象
const finalHash = crypto.createHash("md5");
finalHash.update(strSub);
const finalStr = finalHash.digest("hex");
// 取最终哈希结果的前三个字符并添加到初始值的末尾
strSub += finalStr.substring(0, 3);
return strSub;
} catch (error) {
console.error("处理微信读书 ID 时出现错误:" + error);
return null;
}
};
module.exports = getWereadID;

View File

@@ -1,39 +0,0 @@
{
"opts": {},
"methods": ["HEAD", "OPTIONS", "GET", "PUT", "PATCH", "POST", "DELETE"],
"exclusive": false,
"params": {},
"stack": [
{
"opts": {
"end": true,
"name": null,
"sensitive": false,
"strict": false,
"prefix": ""
},
"name": null,
"methods": ["HEAD", "GET"],
"paramNames": [],
"stack": [null],
"path": "/zhihu",
"regexp": {}
},
{
"opts": {
"end": true,
"name": null,
"sensitive": false,
"strict": false,
"prefix": ""
},
"name": null,
"methods": ["HEAD", "GET"],
"paramNames": [],
"stack": [null],
"path": "/zhihu/new",
"regexp": {}
}
],
"info": { "title": "知乎", "subtitle": "热榜" }
}