mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-12 19:30:48 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdc45c538c | ||
|
|
955c7377d7 | ||
|
|
c71abd8c86 | ||
|
|
ab27a4c908 | ||
|
|
026640a757 | ||
|
|
a1501705c1 | ||
|
|
b321530dcf | ||
|
|
02c6ad8004 | ||
|
|
fff572869e |
@@ -43,19 +43,12 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}) as any,
|
}) as any,
|
||||||
externals: {
|
headScripts: [`./api/env.js`],
|
||||||
react: 'window.React',
|
|
||||||
'react-dom': 'window.ReactDOM',
|
|
||||||
},
|
|
||||||
headScripts: [
|
|
||||||
`./api/env.js`,
|
|
||||||
'https://gw.alipayobjects.com/os/lib/react/18.2.0/umd/react.production.min.js',
|
|
||||||
'https://gw.alipayobjects.com/os/lib/react-dom/18.2.0/umd/react-dom.production.min.js',
|
|
||||||
],
|
|
||||||
copy: [
|
copy: [
|
||||||
{
|
{
|
||||||
from: 'node_modules/monaco-editor/min/vs',
|
from: 'node_modules/monaco-editor/min/vs',
|
||||||
to: 'static/dist/monaco-editor/min/vs',
|
to: 'static/dist/monaco-editor/min/vs',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
npmClient: 'pnpm',
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -126,7 +126,7 @@ curl -sL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|||||||
npm install -g node-pre-gyp pnpm@8.3.1
|
npm install -g node-pre-gyp pnpm@8.3.1
|
||||||
npm install -g @whyour/qinglong
|
npm install -g @whyour/qinglong
|
||||||
qinglong
|
qinglong
|
||||||
# Add the environment variables QL_DIR and QL_DATA_DIR when prompted
|
# Add the environment variables QL_DIR and QL_DATA_DIR when prompted, QL_DATA_DIR must end with /data.
|
||||||
export QL_DIR=""
|
export QL_DIR=""
|
||||||
export QL_DATA_DIR=""
|
export QL_DATA_DIR=""
|
||||||
# Run again
|
# Run again
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ docker run -dit \
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
|
# curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
|
||||||
mkdir qinglong
|
mkdir qinglong && cd $_
|
||||||
wget https://raw.githubusercontent.com/whyour/qinglong/master/docker/docker-compose.yml
|
wget https://raw.githubusercontent.com/whyour/qinglong/master/docker/docker-compose.yml
|
||||||
|
|
||||||
# 启动
|
# 启动
|
||||||
@@ -128,7 +128,7 @@ curl -sL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|||||||
npm install -g node-pre-gyp pnpm@8.3.1
|
npm install -g node-pre-gyp pnpm@8.3.1
|
||||||
npm install -g @whyour/qinglong
|
npm install -g @whyour/qinglong
|
||||||
qinglong
|
qinglong
|
||||||
# 根据提示增加环境变量 QL_DIR 和 QL_DATA_DIR
|
# 根据提示增加环境变量 QL_DIR 和 QL_DATA_DIR,QL_DATA_DIR 必须以 /data 结尾
|
||||||
export QL_DIR=""
|
export QL_DIR=""
|
||||||
export QL_DATA_DIR=""
|
export QL_DATA_DIR=""
|
||||||
# 再次执行
|
# 再次执行
|
||||||
|
|||||||
+3
-1
@@ -145,12 +145,14 @@ export function getPlatform(userAgent: string): 'mobile' | 'desktop' {
|
|||||||
system = 'android'; // android系统
|
system = 'android'; // android系统
|
||||||
} else if (testUa(/ios|iphone|ipad|ipod|iwatch/g)) {
|
} else if (testUa(/ios|iphone|ipad|ipod|iwatch/g)) {
|
||||||
system = 'ios'; // ios系统
|
system = 'ios'; // ios系统
|
||||||
|
} else if (testUa(/openharmony/g)) {
|
||||||
|
system = 'openharmony'; // openharmony系统
|
||||||
}
|
}
|
||||||
|
|
||||||
let platform = 'desktop';
|
let platform = 'desktop';
|
||||||
if (system === 'windows' || system === 'macos' || system === 'linux') {
|
if (system === 'windows' || system === 'macos' || system === 'linux') {
|
||||||
platform = 'desktop';
|
platform = 'desktop';
|
||||||
} else if (system === 'android' || system === 'ios' || testUa(/mobile/g)) {
|
} else if (system === 'android' || system === 'ios' || system === 'openharmony' || testUa(/mobile/g)) {
|
||||||
platform = 'mobile';
|
platform = 'mobile';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-2
@@ -21,6 +21,7 @@ export enum NotificationMode {
|
|||||||
'webhook' = 'webhook',
|
'webhook' = 'webhook',
|
||||||
'chronocat' = 'Chronocat',
|
'chronocat' = 'Chronocat',
|
||||||
'ntfy' = 'ntfy',
|
'ntfy' = 'ntfy',
|
||||||
|
'wxPusherBot' = 'wxPusherBot',
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class NotificationBaseInfo {
|
abstract class NotificationBaseInfo {
|
||||||
@@ -100,6 +101,11 @@ export class IGotNotification extends NotificationBaseInfo {
|
|||||||
export class PushPlusNotification extends NotificationBaseInfo {
|
export class PushPlusNotification extends NotificationBaseInfo {
|
||||||
public pushPlusToken = '';
|
public pushPlusToken = '';
|
||||||
public pushPlusUser = '';
|
public pushPlusUser = '';
|
||||||
|
public pushPlusTemplate = '';
|
||||||
|
public pushplusChannel = '';
|
||||||
|
public pushplusWebhook = '';
|
||||||
|
public pushplusCallbackUrl = '';
|
||||||
|
public pushplusTo = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WePlusBotNotification extends NotificationBaseInfo {
|
export class WePlusBotNotification extends NotificationBaseInfo {
|
||||||
@@ -145,6 +151,13 @@ export class NtfyNotification extends NotificationBaseInfo {
|
|||||||
public ntfyTopic = '';
|
public ntfyTopic = '';
|
||||||
public ntfyPriority = '';
|
public ntfyPriority = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WxPusherBotNotification extends NotificationBaseInfo {
|
||||||
|
public wxPusherBotAppToken = '';
|
||||||
|
public wxPusherBotTopicIds = '';
|
||||||
|
public wxPusherBotUids = '';
|
||||||
|
}
|
||||||
|
|
||||||
export interface NotificationInfo
|
export interface NotificationInfo
|
||||||
extends GoCqHttpBotNotification,
|
extends GoCqHttpBotNotification,
|
||||||
GotifyNotification,
|
GotifyNotification,
|
||||||
@@ -165,5 +178,5 @@ export interface NotificationInfo
|
|||||||
WebhookNotification,
|
WebhookNotification,
|
||||||
ChronocatNotification,
|
ChronocatNotification,
|
||||||
LarkNotification,
|
LarkNotification,
|
||||||
NtfyNotification {}
|
NtfyNotification,
|
||||||
|
WxPusherBotNotification {}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import bodyParser from 'body-parser';
|
|||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import routes from '../api';
|
import routes from '../api';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import jwt, { UnauthorizedError } from 'express-jwt';
|
import { UnauthorizedError, expressjwt } from 'express-jwt';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import { getPlatform, getToken, safeJSONParse } from '../config/util';
|
import { getPlatform, getToken, safeJSONParse } from '../config/util';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
@@ -29,7 +29,7 @@ export default ({ app }: { app: Application }) => {
|
|||||||
target: `http://0.0.0.0:${config.publicPort}/api`,
|
target: `http://0.0.0.0:${config.publicPort}/api`,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
pathRewrite: { '/api/public': '' },
|
pathRewrite: { '/api/public': '' },
|
||||||
logProvider: () => Logger,
|
logger: Logger,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ export default ({ app }: { app: Application }) => {
|
|||||||
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
|
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
jwt({
|
expressjwt({
|
||||||
secret: config.secret,
|
secret: config.secret,
|
||||||
algorithms: ['HS384'],
|
algorithms: ['HS384'],
|
||||||
}).unless({
|
}).unless({
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import bodyParser from 'body-parser';
|
|||||||
import { errors } from 'celebrate';
|
import { errors } from 'celebrate';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import { Application, NextFunction, Request, Response } from 'express';
|
import { Application, NextFunction, Request, Response } from 'express';
|
||||||
import jwt from 'express-jwt';
|
import { expressjwt } from 'express-jwt';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import SystemService from '../services/system';
|
import SystemService from '../services/system';
|
||||||
@@ -16,7 +16,7 @@ export default ({ app }: { app: Application }) => {
|
|||||||
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
|
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
jwt({
|
expressjwt({
|
||||||
secret: config.secret,
|
secret: config.secret,
|
||||||
algorithms: ['HS384'],
|
algorithms: ['HS384'],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ server.bindAsync(
|
|||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
server.start();
|
|
||||||
Logger.debug(`✌️ 定时服务启动成功!`);
|
Logger.debug(`✌️ 定时服务启动成功!`);
|
||||||
console.debug(`✌️ 定时服务启动成功!`);
|
console.debug(`✌️ 定时服务启动成功!`);
|
||||||
process.send?.('ready');
|
process.send?.('ready');
|
||||||
|
|||||||
+63
-10
@@ -36,6 +36,7 @@ export default class NotificationService {
|
|||||||
['lark', this.lark],
|
['lark', this.lark],
|
||||||
['chronocat', this.chronocat],
|
['chronocat', this.chronocat],
|
||||||
['ntfy', this.ntfy],
|
['ntfy', this.ntfy],
|
||||||
|
['wxPusherBot', this.wxPusherBot],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
private title = '';
|
private title = '';
|
||||||
@@ -522,19 +523,26 @@ export default class NotificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async pushPlus() {
|
private async pushPlus() {
|
||||||
const { pushPlusToken, pushPlusUser } = this.params;
|
const { pushPlusToken, pushPlusUser, pushplusWebhook, pushPlusTemplate, pushplusChannel, pushplusCallbackUrl, pushplusTo} = this.params;
|
||||||
const url = `https://www.pushplus.plus/send`;
|
const url = `https://www.pushplus.plus/send`;
|
||||||
try {
|
try {
|
||||||
|
let body = {
|
||||||
|
...this.gotOption,
|
||||||
|
json: {
|
||||||
|
token: `${pushPlusToken}`,
|
||||||
|
title: `${this.title}`,
|
||||||
|
content: `${this.content.replace(/[\n\r]/g, '<br>')}`,
|
||||||
|
topic: `${pushPlusUser || ''}`,
|
||||||
|
template: `${pushPlusTemplate || 'html'}`,
|
||||||
|
channel: `${pushplusChannel || 'wechat'}`,
|
||||||
|
webhook: `${pushplusWebhook || ''}`,
|
||||||
|
callbackUrl: `${pushplusCallbackUrl || ''}`,
|
||||||
|
to: `${pushplusTo || ''}`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const res: any = await got
|
const res: any = await got
|
||||||
.post(url, {
|
.post(url, body)
|
||||||
...this.gotOption,
|
|
||||||
json: {
|
|
||||||
token: `${pushPlusToken}`,
|
|
||||||
title: `${this.title}`,
|
|
||||||
content: `${this.content.replace(/[\n\r]/g, '<br>')}`,
|
|
||||||
topic: `${pushPlusUser || ''}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.json();
|
.json();
|
||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@@ -689,6 +697,51 @@ export default class NotificationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async wxPusherBot() {
|
||||||
|
const { wxPusherBotAppToken, wxPusherBotTopicIds, wxPusherBotUids } = this.params;
|
||||||
|
// 处理 topicIds,将分号分隔的字符串转为数组
|
||||||
|
const topicIds = wxPusherBotTopicIds ? wxPusherBotTopicIds.split(';')
|
||||||
|
.map(id => id.trim())
|
||||||
|
.filter(id => id)
|
||||||
|
.map(id => parseInt(id)) : [];
|
||||||
|
|
||||||
|
// 处理 uids,将分号分隔的字符串转为数组
|
||||||
|
const uids = wxPusherBotUids ? wxPusherBotUids.split(';')
|
||||||
|
.map(uid => uid.trim())
|
||||||
|
.filter(uid => uid) : [];
|
||||||
|
|
||||||
|
// topic_ids 和 uids 至少要有一个
|
||||||
|
if (!topicIds.length && !uids.length) {
|
||||||
|
throw new Error('wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行');
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `https://wxpusher.zjiecode.com/api/send/message`;
|
||||||
|
try {
|
||||||
|
const res: any = await got
|
||||||
|
.post(url, {
|
||||||
|
...this.gotOption,
|
||||||
|
json: {
|
||||||
|
appToken: wxPusherBotAppToken,
|
||||||
|
content: `<h1>${this.title}</h1><br/><div style='white-space: pre-wrap;'>${this.content}</div>`,
|
||||||
|
summary: this.title,
|
||||||
|
contentType: 2,
|
||||||
|
topicIds: topicIds,
|
||||||
|
uids: uids,
|
||||||
|
verifyPayType: 0
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
|
||||||
|
if (res.code === 1000) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(JSON.stringify(res));
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
throw new Error(error.response ? error.response.body : error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private async chronocat() {
|
private async chronocat() {
|
||||||
const { chronocatURL, chronocatQQ, chronocatToken } = this.params;
|
const { chronocatURL, chronocatQQ, chronocatToken } = this.params;
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ export default class ScheduleService {
|
|||||||
const job = new LongIntervalJob(
|
const job = new LongIntervalJob(
|
||||||
{ runImmediately: false, ...schedule },
|
{ runImmediately: false, ...schedule },
|
||||||
task,
|
task,
|
||||||
_id,
|
{ id: _id },
|
||||||
);
|
);
|
||||||
|
|
||||||
this.intervalSchedule.addIntervalJob(job);
|
this.intervalSchedule.addIntervalJob(job);
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ export default class SystemService {
|
|||||||
public async exportData(res: Response) {
|
public async exportData(res: Response) {
|
||||||
try {
|
try {
|
||||||
await promiseExec(
|
await promiseExec(
|
||||||
`cd ${config.rootPath} && tar -zcvf ${config.dataTgzFile} data/`,
|
`cd ${config.dataPath} && cd ../ && tar -zcvf ${config.dataTgzFile} data/`,
|
||||||
);
|
);
|
||||||
res.download(config.dataTgzFile);
|
res.download(config.dataTgzFile);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@@ -414,7 +414,7 @@ export default class SystemService {
|
|||||||
try {
|
try {
|
||||||
await promiseExec(`rm -rf ${path.join(config.tmpPath, 'data')}`);
|
await promiseExec(`rm -rf ${path.join(config.tmpPath, 'data')}`);
|
||||||
const res = await promiseExec(
|
const res = await promiseExec(
|
||||||
`cd ${config.tmpPath} && tar -zxvf data.tgz`,
|
`cd ${config.tmpPath} && tar -zxvf ${config.dataTgzFile}`,
|
||||||
);
|
);
|
||||||
return { code: 200, data: res };
|
return { code: 200, data: res };
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
import { CommandModule } from 'yargs';
|
|
||||||
export const updateCommand: CommandModule = {
|
|
||||||
command: 'update',
|
|
||||||
describe: 'Update and restart qinglong',
|
|
||||||
builder: (yargs) => {
|
|
||||||
return yargs.option('repositority', {
|
|
||||||
type: 'string',
|
|
||||||
alias: 'r',
|
|
||||||
describe: `Specify the release warehouse address of the package`,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
handler: async (argv) => {},
|
|
||||||
};
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import * as yargs from 'yargs';
|
|
||||||
import { green, red } from 'chalk';
|
|
||||||
import { updateCommand } from './commands/update';
|
|
||||||
|
|
||||||
yargs
|
|
||||||
.usage('Usage: ql [command] <options>')
|
|
||||||
.command(updateCommand)
|
|
||||||
.fail((err) => {
|
|
||||||
console.error(`${red(err)}`);
|
|
||||||
})
|
|
||||||
.alias('h', 'help')
|
|
||||||
.showHelp()
|
|
||||||
.recommendCommands().argv;
|
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
# alpine 基础镜像版本
|
image: whyour/qinglong:latest # 基于 Debian 的版本:whyour/qinglong:debian
|
||||||
image: whyour/qinglong:latest
|
|
||||||
# debian-slim 基础镜像版本
|
|
||||||
# image: whyour/qinglong:debian
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/ql/data
|
- ./data:/ql/data
|
||||||
ports:
|
ports:
|
||||||
- "0.0.0.0:5700:5700"
|
- "5700:5700"
|
||||||
environment:
|
environment:
|
||||||
# 部署路径非必须,以斜杠开头和结尾,比如 /test/
|
QlBaseUrl: '/' # 部署路径非必须,以斜杠开头和结尾,比如 /test/
|
||||||
QlBaseUrl: '/'
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
+36
-39
@@ -57,61 +57,59 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grpc/grpc-js": "^1.8.13",
|
"@grpc/grpc-js": "^1.12.3",
|
||||||
"@otplib/preset-default": "^12.0.1",
|
"@otplib/preset-default": "^12.0.1",
|
||||||
"@sentry/node": "^8.26.0",
|
"@sentry/node": "^8.42.0",
|
||||||
"body-parser": "^1.19.2",
|
"body-parser": "^1.20.3",
|
||||||
"celebrate": "^15.0.1",
|
"celebrate": "^15.0.3",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^4.0.1",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"cron-parser": "^4.2.1",
|
"cron-parser": "^4.9.0",
|
||||||
"cross-spawn": "^7.0.3",
|
"cross-spawn": "^7.0.6",
|
||||||
"dayjs": "^1.11.2",
|
"dayjs": "^1.11.13",
|
||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.4.6",
|
||||||
"express": "^4.17.3",
|
"express": "^4.21.1",
|
||||||
"express-jwt": "^6.1.1",
|
"express-jwt": "^8.4.1",
|
||||||
"express-rate-limit": "^7.0.0",
|
"express-rate-limit": "^7.4.1",
|
||||||
"express-urlrewrite": "^1.4.0",
|
"express-urlrewrite": "^2.0.3",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"got": "^11.8.2",
|
"got": "^11.8.2",
|
||||||
"hpagent": "^1.2.0",
|
"hpagent": "^1.2.0",
|
||||||
"http-proxy-middleware": "^2.0.6",
|
"http-proxy-middleware": "^3.0.3",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"multer": "1.4.5-lts.1",
|
"multer": "1.4.5-lts.1",
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
"node-schedule": "^2.1.0",
|
"node-schedule": "^2.1.0",
|
||||||
"nodemailer": "^6.7.2",
|
"nodemailer": "^6.9.16",
|
||||||
"p-queue-cjs": "7.3.4",
|
"p-queue-cjs": "7.3.4",
|
||||||
"protobufjs": "^7.3.0",
|
"protobufjs": "^7.4.0",
|
||||||
"pstree.remy": "^1.1.8",
|
"pstree.remy": "^1.1.8",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.2.2",
|
||||||
"sequelize": "^6.25.5",
|
"sequelize": "^6.37.5",
|
||||||
"serve-handler": "^6.1.3",
|
"serve-handler": "^6.1.6",
|
||||||
"sockjs": "^0.3.24",
|
"sockjs": "^0.3.24",
|
||||||
"sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3",
|
"sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3",
|
||||||
"toad-scheduler": "^1.6.0",
|
"toad-scheduler": "^3.0.1",
|
||||||
"typedi": "^0.10.0",
|
"typedi": "^0.10.0",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^11.0.3",
|
||||||
"winston": "^3.6.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^4.7.1",
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
"yargs": "^17.3.1",
|
|
||||||
"tough-cookie": "^4.0.0",
|
|
||||||
"request-ip": "3.3.0",
|
"request-ip": "3.3.0",
|
||||||
"ip2region": "2.3.0"
|
"ip2region": "2.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"moment": "2.30.1",
|
"moment": "2.30.1",
|
||||||
"@ant-design/icons": "^4.7.0",
|
"@ant-design/icons": "^5.0.1",
|
||||||
"@ant-design/pro-layout": "6.38.22",
|
"@ant-design/pro-layout": "6.38.22",
|
||||||
"@codemirror/view": "^6.34.1",
|
"@codemirror/view": "^6.34.1",
|
||||||
"@codemirror/state": "^6.4.1",
|
"@codemirror/state": "^6.4.1",
|
||||||
"@monaco-editor/react": "4.2.1",
|
"@monaco-editor/react": "4.2.1",
|
||||||
"@react-hook/resize-observer": "^1.2.6",
|
"@react-hook/resize-observer": "^2.0.2",
|
||||||
"react-router-dom": "6.26.1",
|
"react-router-dom": "6.26.1",
|
||||||
"@sentry/react": "^8.26.0",
|
"@sentry/react": "^8.42.0",
|
||||||
"@types/body-parser": "^1.19.2",
|
"@types/body-parser": "^1.19.2",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
"@types/cross-spawn": "^6.0.2",
|
"@types/cross-spawn": "^6.0.2",
|
||||||
@@ -137,16 +135,16 @@
|
|||||||
"@types/request-ip": "0.0.41",
|
"@types/request-ip": "0.0.41",
|
||||||
"@uiw/codemirror-extensions-langs": "^4.21.9",
|
"@uiw/codemirror-extensions-langs": "^4.21.9",
|
||||||
"@uiw/react-codemirror": "^4.21.9",
|
"@uiw/react-codemirror": "^4.21.9",
|
||||||
"@umijs/max": "^4.0.72",
|
"@umijs/max": "^4.3.36",
|
||||||
"@umijs/ssr-darkreader": "^4.9.45",
|
"@umijs/ssr-darkreader": "^4.9.45",
|
||||||
"ahooks": "^3.7.8",
|
"ahooks": "^3.7.8",
|
||||||
"ansi-to-react": "^6.1.6",
|
"ansi-to-react": "^6.1.6",
|
||||||
"antd": "^4.24.8",
|
"antd": "^4.24.8",
|
||||||
"antd-img-crop": "^4.2.3",
|
"antd-img-crop": "^4.23.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"compression-webpack-plugin": "9.2.0",
|
"compression-webpack-plugin": "9.2.0",
|
||||||
"concurrently": "^7.0.0",
|
"concurrently": "^7.0.0",
|
||||||
"react-hotkeys-hook": "^4.4.1",
|
"react-hotkeys-hook": "^4.6.1",
|
||||||
"file-saver": "2.0.2",
|
"file-saver": "2.0.2",
|
||||||
"lint-staged": "^13.0.3",
|
"lint-staged": "^13.0.3",
|
||||||
"monaco-editor": "0.33.0",
|
"monaco-editor": "0.33.0",
|
||||||
@@ -157,14 +155,14 @@
|
|||||||
"qrcode.react": "^1.0.1",
|
"qrcode.react": "^1.0.1",
|
||||||
"query-string": "^7.1.1",
|
"query-string": "^7.1.1",
|
||||||
"rc-tween-one": "^3.0.6",
|
"rc-tween-one": "^3.0.6",
|
||||||
"rc-virtual-list": "3.5.3",
|
"rc-virtual-list": "3.15.0",
|
||||||
"react": "18.2.0",
|
"react": "18.3.1",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
"react-diff-viewer": "^3.1.1",
|
"react-diff-viewer": "^3.1.1",
|
||||||
"react-dnd": "^14.0.2",
|
"react-dnd": "^16.0.1",
|
||||||
"react-dnd-html5-backend": "^14.0.0",
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.3.1",
|
||||||
"react-intl-universal": "^2.6.21",
|
"react-intl-universal": "^2.12.0",
|
||||||
"react-split-pane": "^0.1.92",
|
"react-split-pane": "^0.1.92",
|
||||||
"sockjs-client": "^1.6.0",
|
"sockjs-client": "^1.6.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
@@ -173,7 +171,6 @@
|
|||||||
"typescript": "5.2.2",
|
"typescript": "5.2.2",
|
||||||
"vh-check": "^2.0.5",
|
"vh-check": "^2.0.5",
|
||||||
"virtualizedtableforantd4": "1.3.0",
|
"virtualizedtableforantd4": "1.3.0",
|
||||||
"webpack": "^5.70.0",
|
|
||||||
"yorkie": "^2.0.0"
|
"yorkie": "^2.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+5171
-6098
File diff suppressed because it is too large
Load Diff
+20
-1
@@ -117,6 +117,16 @@ export PUSH_PLUS_TOKEN=""
|
|||||||
## 下方填写您的一对多推送的 "群组编码" ,(一对多推送下面->您的群组(如无则新建)->群组编码)
|
## 下方填写您的一对多推送的 "群组编码" ,(一对多推送下面->您的群组(如无则新建)->群组编码)
|
||||||
## 1. 需订阅者扫描二维码 2、如果您是创建群组所属人,也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送
|
## 1. 需订阅者扫描二维码 2、如果您是创建群组所属人,也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送
|
||||||
export PUSH_PLUS_USER=""
|
export PUSH_PLUS_USER=""
|
||||||
|
## 发送模板,支持html,txt,json,markdown,cloudMonitor,jenkins,route,pay
|
||||||
|
export PUSH_PLUS_TEMPLATE="html"
|
||||||
|
## 发送渠道,支持wechat,webhook,cp,mail,sms
|
||||||
|
export PUSH_PLUS_CHANNEL="wechat"
|
||||||
|
## webhook编码,可在pushplus公众号上扩展配置出更多渠道
|
||||||
|
export PUSH_PLUS_WEBHOOK=""
|
||||||
|
## 发送结果回调地址,会把推送最终结果通知到这个地址上
|
||||||
|
export PUSH_PLUS_CALLBACKURL=""
|
||||||
|
## 好友令牌,微信公众号渠道填写好友令牌,企业微信渠道填写企业微信用户id
|
||||||
|
export PUSH_PLUS_TO=""
|
||||||
|
|
||||||
## 9. 微加机器人
|
## 9. 微加机器人
|
||||||
## 官方网站:http://www.weplusbot.com
|
## 官方网站:http://www.weplusbot.com
|
||||||
@@ -220,8 +230,17 @@ export NTFY_URL=""
|
|||||||
export NTFY_TOPIC=""
|
export NTFY_TOPIC=""
|
||||||
export NTFY_PRIORITY="3"
|
export NTFY_PRIORITY="3"
|
||||||
|
|
||||||
|
## 21. wxPusher
|
||||||
|
## 官方文档: https://wxpusher.zjiecode.com/docs/
|
||||||
|
## 管理后台: https://wxpusher.zjiecode.com/admin/
|
||||||
|
## wxPusher 的 appToken
|
||||||
|
export WXPUSHER_APP_TOKEN=""
|
||||||
|
## wxPusher 的 topicIds,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
|
export WXPUSHER_TOPIC_IDS=""
|
||||||
|
## wxPusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
|
export WXPUSHER_UIDS=""
|
||||||
|
|
||||||
## 21. 自定义通知
|
## 22. 自定义通知
|
||||||
## 自定义通知 接收回调的URL
|
## 自定义通知 接收回调的URL
|
||||||
export WEBHOOK_URL=""
|
export WEBHOOK_URL=""
|
||||||
## WEBHOOK_BODY 和 WEBHOOK_HEADERS 多个参数时,直接换行或者使用 $'\n' 连接多行字符串,比如 export dd="line 1"$'\n'"line 2"
|
## WEBHOOK_BODY 和 WEBHOOK_HEADERS 多个参数时,直接换行或者使用 $'\n' 连接多行字符串,比如 export dd="line 1"$'\n'"line 2"
|
||||||
|
|||||||
+90
-8
@@ -40,9 +40,15 @@ const push_config = {
|
|||||||
CHAT_URL: '', // synology chat url
|
CHAT_URL: '', // synology chat url
|
||||||
CHAT_TOKEN: '', // synology chat token
|
CHAT_TOKEN: '', // synology chat token
|
||||||
|
|
||||||
// 官方文档:http://www.pushplus.plus/
|
// 官方文档:https://www.pushplus.plus/
|
||||||
PUSH_PLUS_TOKEN: '', // push+ 微信推送的用户令牌
|
PUSH_PLUS_TOKEN: '', // pushplus 推送的用户令牌
|
||||||
PUSH_PLUS_USER: '', // push+ 微信推送的群组编码
|
PUSH_PLUS_USER: '', // pushplus 推送的群组编码
|
||||||
|
PUSH_PLUS_TEMPLATE: 'html', // pushplus 发送模板,支持html,txt,json,markdown,cloudMonitor,jenkins,route,pay
|
||||||
|
PUSH_PLUS_CHANNEL: 'wechat', // pushplus 发送渠道,支持wechat,webhook,cp,mail,sms
|
||||||
|
PUSH_PLUS_WEBHOOK: '', // pushplus webhook编码,可在pushplus公众号上扩展配置出更多渠道
|
||||||
|
PUSH_PLUS_CALLBACKURL: '', // pushplus 发送结果回调地址,会把推送最终结果通知到这个地址上
|
||||||
|
PUSH_PLUS_TO: '', // pushplus 好友令牌,微信公众号渠道填写好友令牌,企业微信渠道填写企业微信用户id
|
||||||
|
|
||||||
|
|
||||||
// 微加机器人,官方网站:https://www.weplusbot.com/
|
// 微加机器人,官方网站:https://www.weplusbot.com/
|
||||||
WE_PLUS_BOT_TOKEN: '', // 微加机器人的用户令牌
|
WE_PLUS_BOT_TOKEN: '', // 微加机器人的用户令牌
|
||||||
@@ -99,6 +105,12 @@ const push_config = {
|
|||||||
NTFY_URL: '', // ntfy地址,如https://ntfy.sh,默认为https://ntfy.sh
|
NTFY_URL: '', // ntfy地址,如https://ntfy.sh,默认为https://ntfy.sh
|
||||||
NTFY_TOPIC: '', // ntfy的消息应用topic
|
NTFY_TOPIC: '', // ntfy的消息应用topic
|
||||||
NTFY_PRIORITY: '3', // 推送消息优先级,默认为3
|
NTFY_PRIORITY: '3', // 推送消息优先级,默认为3
|
||||||
|
|
||||||
|
// 官方文档: https://wxpusher.zjiecode.com/docs/
|
||||||
|
// 管理后台: https://wxpusher.zjiecode.com/admin/
|
||||||
|
WXPUSHER_APP_TOKEN: '', // wxpusher 的 appToken
|
||||||
|
WXPUSHER_TOPIC_IDS: '', // wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
|
WXPUSHER_UIDS: '', // wxpusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const key in push_config) {
|
for (const key in push_config) {
|
||||||
@@ -765,7 +777,7 @@ function iGotNotify(text, desp, params = {}) {
|
|||||||
|
|
||||||
function pushPlusNotify(text, desp) {
|
function pushPlusNotify(text, desp) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const { PUSH_PLUS_TOKEN, PUSH_PLUS_USER } = push_config;
|
const { PUSH_PLUS_TOKEN, PUSH_PLUS_USER, PUSH_PLUS_TEMPLATE, PUSH_PLUS_CHANNEL, PUSH_PLUS_WEBHOOK, PUSH_PLUS_CALLBACKURL, PUSH_PLUS_TO } = push_config;
|
||||||
if (PUSH_PLUS_TOKEN) {
|
if (PUSH_PLUS_TOKEN) {
|
||||||
desp = desp.replace(/[\n\r]/g, '<br>'); // 默认为html, 不支持plaintext
|
desp = desp.replace(/[\n\r]/g, '<br>'); // 默认为html, 不支持plaintext
|
||||||
const body = {
|
const body = {
|
||||||
@@ -773,6 +785,11 @@ function pushPlusNotify(text, desp) {
|
|||||||
title: `${text}`,
|
title: `${text}`,
|
||||||
content: `${desp}`,
|
content: `${desp}`,
|
||||||
topic: `${PUSH_PLUS_USER}`,
|
topic: `${PUSH_PLUS_USER}`,
|
||||||
|
template: `${PUSH_PLUS_TEMPLATE}`,
|
||||||
|
channel: `${PUSH_PLUS_CHANNEL}`,
|
||||||
|
webhook: `${PUSH_PLUS_WEBHOOK}`,
|
||||||
|
callbackUrl: `${PUSH_PLUS_CALLBACKURL}`,
|
||||||
|
to: `${PUSH_PLUS_TO}`
|
||||||
};
|
};
|
||||||
const options = {
|
const options = {
|
||||||
url: `https://www.pushplus.plus/send`,
|
url: `https://www.pushplus.plus/send`,
|
||||||
@@ -786,7 +803,7 @@ function pushPlusNotify(text, desp) {
|
|||||||
try {
|
try {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(
|
console.log(
|
||||||
`Push+ 发送${
|
`pushplus 发送${
|
||||||
PUSH_PLUS_USER ? '一对多' : '一对一'
|
PUSH_PLUS_USER ? '一对多' : '一对一'
|
||||||
}通知消息失败😞\n`,
|
}通知消息失败😞\n`,
|
||||||
err,
|
err,
|
||||||
@@ -794,13 +811,13 @@ function pushPlusNotify(text, desp) {
|
|||||||
} else {
|
} else {
|
||||||
if (data.code === 200) {
|
if (data.code === 200) {
|
||||||
console.log(
|
console.log(
|
||||||
`Push+ 发送${
|
`pushplus 发送${
|
||||||
PUSH_PLUS_USER ? '一对多' : '一对一'
|
PUSH_PLUS_USER ? '一对多' : '一对一'
|
||||||
}通知消息完成🎉\n`,
|
}通知请求成功🎉,可根据流水号查询推送结果:${data.data}\n注意:请求成功并不代表推送成功,如未收到消息,请到pushplus官网使用流水号查询推送最终结果`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
`Push+ 发送${
|
`pushplus 发送${
|
||||||
PUSH_PLUS_USER ? '一对多' : '一对一'
|
PUSH_PLUS_USER ? '一对多' : '一对一'
|
||||||
}通知消息异常 ${data.msg}\n`,
|
}通知消息异常 ${data.msg}\n`,
|
||||||
);
|
);
|
||||||
@@ -1235,6 +1252,70 @@ function ntfyNotify(text, desp) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wxPusherNotify(text, desp) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const { WXPUSHER_APP_TOKEN, WXPUSHER_TOPIC_IDS, WXPUSHER_UIDS } = push_config;
|
||||||
|
if (WXPUSHER_APP_TOKEN) {
|
||||||
|
// 处理topic_ids,将分号分隔的字符串转为数组
|
||||||
|
const topicIds = WXPUSHER_TOPIC_IDS ? WXPUSHER_TOPIC_IDS.split(';')
|
||||||
|
.map(id => id.trim())
|
||||||
|
.filter(id => id)
|
||||||
|
.map(id => parseInt(id)) : [];
|
||||||
|
|
||||||
|
// 处理uids,将分号分隔的字符串转为数组
|
||||||
|
const uids = WXPUSHER_UIDS ? WXPUSHER_UIDS.split(';')
|
||||||
|
.map(uid => uid.trim())
|
||||||
|
.filter(uid => uid) : [];
|
||||||
|
|
||||||
|
// topic_ids uids 至少有一个
|
||||||
|
if (!topicIds.length && !uids.length) {
|
||||||
|
console.log("wxpusher 服务的 WXPUSHER_TOPIC_IDS 和 WXPUSHER_UIDS 至少设置一个!!\n取消推送");
|
||||||
|
return resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
appToken: WXPUSHER_APP_TOKEN,
|
||||||
|
content: `<h1>${text}</h1><br/><div style='white-space: pre-wrap;'>${desp}</div>`,
|
||||||
|
summary: text,
|
||||||
|
contentType: 2,
|
||||||
|
topicIds: topicIds,
|
||||||
|
uids: uids,
|
||||||
|
verifyPayType: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
url: 'https://wxpusher.zjiecode.com/api/send/message',
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
timeout
|
||||||
|
};
|
||||||
|
|
||||||
|
$.post(options, (err, resp, data) => {
|
||||||
|
try {
|
||||||
|
if (err) {
|
||||||
|
console.log('wxpusher发送通知消息失败!\n', err);
|
||||||
|
} else {
|
||||||
|
if (data.code === 1000) {
|
||||||
|
console.log('wxpusher发送通知消息完成!');
|
||||||
|
} else {
|
||||||
|
console.log(`wxpusher发送通知消息异常:${data.msg}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$.logErr(e, resp);
|
||||||
|
} finally {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('wxpusher 服务的 WXPUSHER_APP_TOKEN 未设置!!\n取消推送');
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function parseString(input, valueFormatFn) {
|
function parseString(input, valueFormatFn) {
|
||||||
const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g;
|
const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g;
|
||||||
@@ -1365,6 +1446,7 @@ async function sendNotify(text, desp, params = {}) {
|
|||||||
webhookNotify(text, desp), // 自定义通知
|
webhookNotify(text, desp), // 自定义通知
|
||||||
qmsgNotify(text, desp), // 自定义通知
|
qmsgNotify(text, desp), // 自定义通知
|
||||||
ntfyNotify(text, desp), // Ntfy
|
ntfyNotify(text, desp), // Ntfy
|
||||||
|
wxPusherNotify(text, desp), // wxpusher
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+77
-6
@@ -72,8 +72,13 @@ push_config = {
|
|||||||
'CHAT_URL': '', # synology chat url
|
'CHAT_URL': '', # synology chat url
|
||||||
'CHAT_TOKEN': '', # synology chat token
|
'CHAT_TOKEN': '', # synology chat token
|
||||||
|
|
||||||
'PUSH_PLUS_TOKEN': '', # push+ 微信推送的用户令牌
|
'PUSH_PLUS_TOKEN': '', # pushplus 推送的用户令牌
|
||||||
'PUSH_PLUS_USER': '', # push+ 微信推送的群组编码
|
'PUSH_PLUS_USER': '', # pushplus 推送的群组编码
|
||||||
|
'PUSH_PLUS_TEMPLATE': 'html', # pushplus 发送模板,支持html,txt,json,markdown,cloudMonitor,jenkins,route,pay
|
||||||
|
'PUSH_PLUS_CHANNEL': 'wechat', # pushplus 发送渠道,支持wechat,webhook,cp,mail,sms
|
||||||
|
'PUSH_PLUS_WEBHOOK': '', # pushplus webhook编码,可在pushplus公众号上扩展配置出更多渠道
|
||||||
|
'PUSH_PLUS_CALLBACKURL': '', # pushplus 发送结果回调地址,会把推送最终结果通知到这个地址上
|
||||||
|
'PUSH_PLUS_TO': '', # pushplus 好友令牌,微信公众号渠道填写好友令牌,企业微信渠道填写企业微信用户id
|
||||||
|
|
||||||
'WE_PLUS_BOT_TOKEN': '', # 微加机器人的用户令牌
|
'WE_PLUS_BOT_TOKEN': '', # 微加机器人的用户令牌
|
||||||
'WE_PLUS_BOT_RECEIVER': '', # 微加机器人的消息接收者
|
'WE_PLUS_BOT_RECEIVER': '', # 微加机器人的消息接收者
|
||||||
@@ -121,6 +126,10 @@ push_config = {
|
|||||||
'NTFY_URL': '', # ntfy地址,如https://ntfy.sh
|
'NTFY_URL': '', # ntfy地址,如https://ntfy.sh
|
||||||
'NTFY_TOPIC': '', # ntfy的消息应用topic
|
'NTFY_TOPIC': '', # ntfy的消息应用topic
|
||||||
'NTFY_PRIORITY':'3', # 推送消息优先级,默认为3
|
'NTFY_PRIORITY':'3', # 推送消息优先级,默认为3
|
||||||
|
|
||||||
|
'WXPUSHER_APP_TOKEN': '', # wxpusher 的 appToken 官方文档: https://wxpusher.zjiecode.com/docs/ 管理后台: https://wxpusher.zjiecode.com/admin/
|
||||||
|
'WXPUSHER_TOPIC_IDS': '', # wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
|
'WXPUSHER_UIDS': '', # wxpusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
|
||||||
}
|
}
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
@@ -364,26 +373,35 @@ def chat(title: str, content: str) -> None:
|
|||||||
|
|
||||||
def pushplus_bot(title: str, content: str) -> None:
|
def pushplus_bot(title: str, content: str) -> None:
|
||||||
"""
|
"""
|
||||||
通过 push+ 推送消息。
|
通过 pushplus 推送消息。
|
||||||
"""
|
"""
|
||||||
if not push_config.get("PUSH_PLUS_TOKEN"):
|
if not push_config.get("PUSH_PLUS_TOKEN"):
|
||||||
print("PUSHPLUS 服务的 PUSH_PLUS_TOKEN 未设置!!\n取消推送")
|
print("PUSHPLUS 服务的 PUSH_PLUS_TOKEN 未设置!!\n取消推送")
|
||||||
return
|
return
|
||||||
print("PUSHPLUS 服务启动")
|
print("PUSHPLUS 服务启动")
|
||||||
|
|
||||||
url = "http://www.pushplus.plus/send"
|
url = "https://www.pushplus.plus/send"
|
||||||
data = {
|
data = {
|
||||||
"token": push_config.get("PUSH_PLUS_TOKEN"),
|
"token": push_config.get("PUSH_PLUS_TOKEN"),
|
||||||
"title": title,
|
"title": title,
|
||||||
"content": content,
|
"content": content,
|
||||||
"topic": push_config.get("PUSH_PLUS_USER"),
|
"topic": push_config.get("PUSH_PLUS_USER"),
|
||||||
|
"template": push_config.get("PUSH_PLUS_TEMPLATE"),
|
||||||
|
"channel": push_config.get("PUSH_PLUS_CHANNEL"),
|
||||||
|
"webhook": push_config.get("PUSH_PLUS_WEBHOOK"),
|
||||||
|
"callbackUrl": push_config.get("PUSH_PLUS_CALLBACKURL"),
|
||||||
|
"to": push_config.get("PUSH_PLUS_TO")
|
||||||
}
|
}
|
||||||
body = json.dumps(data).encode(encoding="utf-8")
|
body = json.dumps(data).encode(encoding="utf-8")
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
response = requests.post(url=url, data=body, headers=headers).json()
|
response = requests.post(url=url, data=body, headers=headers).json()
|
||||||
|
|
||||||
if response["code"] == 200:
|
code = response["code"]
|
||||||
print("PUSHPLUS 推送成功!")
|
if code == 200:
|
||||||
|
print("PUSHPLUS 推送请求成功,可根据流水号查询推送结果:"+ response["data"])
|
||||||
|
print("注意:请求成功并不代表推送成功,如未收到消息,请到pushplus官网使用流水号查询推送最终结果")
|
||||||
|
elif code == 900 or code == 903 or code == 905 or code == 999 :
|
||||||
|
print(response["msg"])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
url_old = "http://pushplus.hxtrip.com/send"
|
url_old = "http://pushplus.hxtrip.com/send"
|
||||||
@@ -821,6 +839,57 @@ def ntfy(title: str, content: str) -> None:
|
|||||||
else:
|
else:
|
||||||
print("Ntfy 推送失败!错误信息:", response.text)
|
print("Ntfy 推送失败!错误信息:", response.text)
|
||||||
|
|
||||||
|
|
||||||
|
def wxpusher_bot(title: str, content: str) -> None:
|
||||||
|
"""
|
||||||
|
通过 wxpusher 推送消息。
|
||||||
|
支持的环境变量:
|
||||||
|
- WXPUSHER_APP_TOKEN: appToken
|
||||||
|
- WXPUSHER_TOPIC_IDS: 主题ID, 多个用英文分号;分隔
|
||||||
|
- WXPUSHER_UIDS: 用户ID, 多个用英文分号;分隔
|
||||||
|
"""
|
||||||
|
if not push_config.get("WXPUSHER_APP_TOKEN"):
|
||||||
|
print("wxpusher 服务的 WXPUSHER_APP_TOKEN 未设置!!\n取消推送")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
url = "https://wxpusher.zjiecode.com/api/send/message"
|
||||||
|
|
||||||
|
# 处理topic_ids和uids,将分号分隔的字符串转为数组
|
||||||
|
topic_ids = []
|
||||||
|
if push_config.get("WXPUSHER_TOPIC_IDS"):
|
||||||
|
topic_ids = [int(id.strip()) for id in push_config.get("WXPUSHER_TOPIC_IDS").split(";") if id.strip()]
|
||||||
|
|
||||||
|
uids = []
|
||||||
|
if push_config.get("WXPUSHER_UIDS"):
|
||||||
|
uids = [uid.strip() for uid in push_config.get("WXPUSHER_UIDS").split(";") if uid.strip()]
|
||||||
|
|
||||||
|
# topic_ids uids 至少有一个
|
||||||
|
if not topic_ids and not uids:
|
||||||
|
print("wxpusher 服务的 WXPUSHER_TOPIC_IDS 和 WXPUSHER_UIDS 至少设置一个!!\n取消推送")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("wxpusher 服务启动")
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"appToken": push_config.get("WXPUSHER_APP_TOKEN"),
|
||||||
|
"content": f"<h1>{title}</h1><br/><div style='white-space: pre-wrap;'>{content}</div>",
|
||||||
|
"summary": title,
|
||||||
|
"contentType": 2,
|
||||||
|
"topicIds": topic_ids,
|
||||||
|
"uids": uids,
|
||||||
|
"verifyPayType": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
headers = {"Content-Type": "application/json"}
|
||||||
|
response = requests.post(url=url, json=data, headers=headers).json()
|
||||||
|
|
||||||
|
if response.get("code") == 1000:
|
||||||
|
print("wxpusher 推送成功!")
|
||||||
|
else:
|
||||||
|
print(f"wxpusher 推送失败!错误信息:{response.get('msg')}")
|
||||||
|
|
||||||
|
|
||||||
def parse_headers(headers):
|
def parse_headers(headers):
|
||||||
if not headers:
|
if not headers:
|
||||||
return {}
|
return {}
|
||||||
@@ -983,6 +1052,8 @@ def add_notify_function():
|
|||||||
notify_function.append(custom_notify)
|
notify_function.append(custom_notify)
|
||||||
if push_config.get("NTFY_TOPIC"):
|
if push_config.get("NTFY_TOPIC"):
|
||||||
notify_function.append(ntfy)
|
notify_function.append(ntfy)
|
||||||
|
if push_config.get("WXPUSHER_APP_TOKEN") and (push_config.get("WXPUSHER_TOPIC_IDS") or push_config.get("WXPUSHER_UIDS")):
|
||||||
|
notify_function.append(wxpusher_bot)
|
||||||
if not notify_function:
|
if not notify_function:
|
||||||
print(f"无推送渠道,请检查通知变量是否正确")
|
print(f"无推送渠道,请检查通知变量是否正确")
|
||||||
return notify_function
|
return notify_function
|
||||||
|
|||||||
@@ -379,6 +379,11 @@
|
|||||||
"iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX": "iGot information push key, e.g., https://push.hellyw.com/XXXXXXXX",
|
"iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX": "iGot information push key, e.g., https://push.hellyw.com/XXXXXXXX",
|
||||||
"微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/": "After WeChat scan login, one-to-one or one-to-many push using the provided token (your Token). If PUSH_PLUS_USER is not provided, it defaults to one-to-one push. See reference at https://www.pushplus.plus/",
|
"微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/": "After WeChat scan login, one-to-one or one-to-many push using the provided token (your Token). If PUSH_PLUS_USER is not provided, it defaults to one-to-one push. See reference at https://www.pushplus.plus/",
|
||||||
"一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "The 'group code' for one-to-many push (one-to-many push -> your group (if none, create one) -> group code). If you are the creator of the group, you need to click 'View QR code' to scan and bind, otherwise, you won't receive group messages.",
|
"一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "The 'group code' for one-to-many push (one-to-many push -> your group (if none, create one) -> group code). If you are the creator of the group, you need to click 'View QR code' to scan and bind, otherwise, you won't receive group messages.",
|
||||||
|
"发送模板": "send template, can use type: 'html,txt,json,markdown,cloudMonitor,jenkins,route,pay'",
|
||||||
|
"发送渠道": "send channel, can use type: 'wechat,webhook,cp,mail,sms'",
|
||||||
|
"webhook编码": "webhook code",
|
||||||
|
"发送结果回调地址": "send result callback url",
|
||||||
|
"好友令牌": "friend token",
|
||||||
"用户令牌,扫描登录后 我的—>设置->令牌 中获取,参考 https://www.weplusbot.com/": "Token, which can be obtained after scanning and logging in, is available under 'My Account' -> 'Settings' -> 'Tokens'. Please refer to the instructions for detailed steps: https://www.weplusbot.com/",
|
"用户令牌,扫描登录后 我的—>设置->令牌 中获取,参考 https://www.weplusbot.com/": "Token, which can be obtained after scanning and logging in, is available under 'My Account' -> 'Settings' -> 'Tokens'. Please refer to the instructions for detailed steps: https://www.weplusbot.com/",
|
||||||
"消息接收人": "message recipient",
|
"消息接收人": "message recipient",
|
||||||
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "Version, you can specify 'pro' for the Professional version and 'personal' for the Personal version. If left blank, it will default to the Professional version.",
|
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "Version, you can specify 'pro' for the Professional version and 'personal' for the Personal version. If left blank, it will default to the Professional version.",
|
||||||
@@ -390,6 +395,9 @@
|
|||||||
"自建的PushMeServer消息接口地址,例如:http://127.0.0.1:3010,不填则使用官方消息接口": "The self built PushMeServer message interface address, for example: http://127.0.0.1:3010 If left blank, use the official message interface",
|
"自建的PushMeServer消息接口地址,例如:http://127.0.0.1:3010,不填则使用官方消息接口": "The self built PushMeServer message interface address, for example: http://127.0.0.1:3010 If left blank, use the official message interface",
|
||||||
"ntfy的url地址,例如 https://ntfy.sh'": "The URL address of ntfy, for example, https://ntfy.sh.",
|
"ntfy的url地址,例如 https://ntfy.sh'": "The URL address of ntfy, for example, https://ntfy.sh.",
|
||||||
"ntfy的消息应用topic": "The topic for ntfy's messaging application.",
|
"ntfy的消息应用topic": "The topic for ntfy's messaging application.",
|
||||||
|
"wxPusherBot的appToken": "wxPusherBot's appToken, obtain according to docs https://wxpusher.zjiecode.com/docs/",
|
||||||
|
"wxPusherBot的topicIds": "wxPusherBot's topicIds, at least one of topicIds or uids must be configured",
|
||||||
|
"wxPusherBot的uids": "wxPusherBot's uids, at least one of topicIds or uids must be configured",
|
||||||
"请求方法": "Request Method",
|
"请求方法": "Request Method",
|
||||||
"请求头Content-Type": "Request Header Content-Type",
|
"请求头Content-Type": "Request Header Content-Type",
|
||||||
"请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置": "Request URL should start with http or https. URL or body must contain $title, $content is optional and corresponds to the API content position.",
|
"请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置": "Request URL should start with http or https. URL or body must contain $title, $content is optional and corresponds to the API content position.",
|
||||||
|
|||||||
@@ -377,8 +377,13 @@
|
|||||||
"好友": "好友",
|
"好友": "好友",
|
||||||
"要发送的用户昵称或群名,如果目标是群,需要填群名,如果目标是好友,需要填好友昵称": "要发送的用户昵称或群名,如果目标是群,需要填群名,如果目标是好友,需要填好友昵称",
|
"要发送的用户昵称或群名,如果目标是群,需要填群名,如果目标是好友,需要填好友昵称": "要发送的用户昵称或群名,如果目标是群,需要填群名,如果目标是好友,需要填好友昵称",
|
||||||
"iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX": "iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX",
|
"iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX": "iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX",
|
||||||
"微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/": "微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/",
|
"微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/": "微信扫码登录后一对一推送或一对多推送下面的token(你的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/",
|
||||||
"一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)",
|
"一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)": "一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)",
|
||||||
|
"发送模板": "发送模板,支持html,txt,json,markdown,cloudMonitor,jenkins,route,pay",
|
||||||
|
"发送渠道": "发送渠道,支持wechat,webhook,cp,mail,sms",
|
||||||
|
"webhook编码": "webhook编码,可在pushplus公众号上扩展配置出更多渠道",
|
||||||
|
"发送结果回调地址": "发送结果回调地址,会把推送最终结果通知到这个地址上",
|
||||||
|
"好友令牌": "好友令牌,微信公众号渠道填写好友令牌,企业微信渠道填写企业微信用户id",
|
||||||
"用户令牌,扫描登录后 我的—>设置->令牌 中获取,参考 https://www.weplusbot.com/": "用户令牌,扫描登录后 我的—>设置->令牌 中获取,参考 https://www.weplusbot.com/",
|
"用户令牌,扫描登录后 我的—>设置->令牌 中获取,参考 https://www.weplusbot.com/": "用户令牌,扫描登录后 我的—>设置->令牌 中获取,参考 https://www.weplusbot.com/",
|
||||||
"消息接收人": "消息接收人",
|
"消息接收人": "消息接收人",
|
||||||
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版",
|
"调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版": "调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版",
|
||||||
@@ -390,6 +395,9 @@
|
|||||||
"自建的PushMeServer消息接口地址,例如:http://127.0.0.1:3010,不填则使用官方消息接口": "自建的PushMeServer消息接口地址,例如:http://127.0.0.1:3010,不填则使用官方消息接口",
|
"自建的PushMeServer消息接口地址,例如:http://127.0.0.1:3010,不填则使用官方消息接口": "自建的PushMeServer消息接口地址,例如:http://127.0.0.1:3010,不填则使用官方消息接口",
|
||||||
"ntfy的url地址,例如 https://ntfy.sh": "ntfy的url地址,例如 https://ntfy.sh",
|
"ntfy的url地址,例如 https://ntfy.sh": "ntfy的url地址,例如 https://ntfy.sh",
|
||||||
"ntfy的消息应用topic": "ntfy的消息应用topic",
|
"ntfy的消息应用topic": "ntfy的消息应用topic",
|
||||||
|
"wxPusherBot的appToken": "wxPusherBot的appToken, 按照文档获取 https://wxpusher.zjiecode.com/docs/",
|
||||||
|
"wxPusherBot的topicIds": "wxPusherBot的topicIds, topicIds 和 uids 至少配置一个才行",
|
||||||
|
"wxPusherBot的uids": "wxPusherBot的uids, topicIds 和 uids 至少配置一个才行",
|
||||||
"请求方法": "请求方法",
|
"请求方法": "请求方法",
|
||||||
"请求头Content-Type": "请求头Content-Type",
|
"请求头Content-Type": "请求头Content-Type",
|
||||||
"请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置": "请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置",
|
"请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置": "请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置",
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ export default {
|
|||||||
{ value: 'iGot', label: 'IGot' },
|
{ value: 'iGot', label: 'IGot' },
|
||||||
{ value: 'pushPlus', label: 'PushPlus' },
|
{ value: 'pushPlus', label: 'PushPlus' },
|
||||||
{ value: 'wePlusBot', label: intl.get('微加机器人') },
|
{ value: 'wePlusBot', label: intl.get('微加机器人') },
|
||||||
|
{ value: 'wxPusherBot', label: 'wxPusher' },
|
||||||
{ value: 'chat', label: intl.get('群晖chat') },
|
{ value: 'chat', label: intl.get('群晖chat') },
|
||||||
{ value: 'email', label: intl.get('邮箱') },
|
{ value: 'email', label: intl.get('邮箱') },
|
||||||
{ value: 'lark', label: intl.get('飞书机器人') },
|
{ value: 'lark', label: intl.get('飞书机器人') },
|
||||||
@@ -326,6 +327,36 @@ export default {
|
|||||||
'一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)',
|
'一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)',
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'pushplusTemplate',
|
||||||
|
tip: intl.get(
|
||||||
|
'发送模板',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'pushplusChannel',
|
||||||
|
tip: intl.get(
|
||||||
|
'发送渠道',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'pushplusWebhook',
|
||||||
|
tip: intl.get(
|
||||||
|
'webhook编码',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'pushplusCallbackUrl',
|
||||||
|
tip: intl.get(
|
||||||
|
'发送结果回调地址',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'pushplusTo',
|
||||||
|
tip: intl.get(
|
||||||
|
'好友令牌',
|
||||||
|
),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
wePlusBot: [
|
wePlusBot: [
|
||||||
{
|
{
|
||||||
@@ -348,6 +379,23 @@ export default {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
wxPusherBot: [
|
||||||
|
{
|
||||||
|
label: 'wxPusherBotAppToken',
|
||||||
|
tip: intl.get('wxPusherBot的appToken'),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'wxPusherBotTopicIds',
|
||||||
|
tip: intl.get('wxPusherBot的topicIds'),
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'wxPusherBotUids',
|
||||||
|
tip: intl.get('wxPusherBot的uids'),
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
lark: [
|
lark: [
|
||||||
{
|
{
|
||||||
label: 'larkKey',
|
label: 'larkKey',
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { LANG_MAP, LOG_END_SYMBOL } from './const';
|
import { LANG_MAP, LOG_END_SYMBOL } from './const';
|
||||||
import cron_parser from 'cron-parser';
|
import cron_parser from 'cron-parser';
|
||||||
|
import { ICrontab } from '@/pages/crontab/type';
|
||||||
|
|
||||||
export default function browserType() {
|
export default function browserType() {
|
||||||
// 权重:系统 + 系统版本 > 平台 > 内核 + 载体 + 内核版本 + 载体版本 > 外壳 + 外壳版本
|
// 权重:系统 + 系统版本 > 平台 > 内核 + 载体 + 内核版本 + 载体版本 > 外壳 + 外壳版本
|
||||||
@@ -343,12 +344,12 @@ export function parseCrontab(schedule: string): Date | null {
|
|||||||
|
|
||||||
export function getCrontabsNextDate(
|
export function getCrontabsNextDate(
|
||||||
schedule: string,
|
schedule: string,
|
||||||
extra_schedules: string[],
|
extra_schedules: ICrontab['extra_schedules'],
|
||||||
): Date | null {
|
): Date | null {
|
||||||
let date = parseCrontab(schedule);
|
let date = parseCrontab(schedule);
|
||||||
if (extra_schedules?.length) {
|
if (extra_schedules?.length) {
|
||||||
extra_schedules.forEach((x) => {
|
extra_schedules.forEach((x) => {
|
||||||
const _date = parseCrontab(x);
|
const _date = parseCrontab(x.schedule);
|
||||||
if (_date && (!date || _date < date)) {
|
if (_date && (!date || _date < date)) {
|
||||||
date = _date;
|
date = _date;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-10
@@ -1,11 +1,9 @@
|
|||||||
version: 2.17.12
|
version: 2.17.13
|
||||||
changeLogLink: https://t.me/jiao_long/422
|
changeLogLink: https://t.me/jiao_long/423
|
||||||
publishTime: 2024-10-26 15:30
|
publishTime: 2024-12-21 23:30
|
||||||
changeLog: |
|
changeLog: |
|
||||||
1. 定时任务支持复制
|
1. 新增 wxPusher 通知
|
||||||
2. 增加 ntfy 通知
|
2. 完善 pushplus 通知
|
||||||
3. 适配Server酱APP分支(Server酱³),移除已废弃的旧版api入口
|
3. 修复任务列表下次运行时间展示
|
||||||
4. 修复任务命令带有 -m 参数时,日志目录生成异常
|
4. 修复本地部署设置 dataPath 后,备份目录可能错误
|
||||||
5. 修复登录日志无法自动保存
|
5. h5 登录增加识别鸿蒙系统
|
||||||
6. 移除任务执行前后的脚本参数
|
|
||||||
7. 定时任务外漏视图改为 10 个
|
|
||||||
|
|||||||
Reference in New Issue
Block a user