@whyour/qinglong 2.20.2-3 → 2.21.0-10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/.env.example +5 -0
  2. package/AGENTS.md +43 -0
  3. package/README-en.md +11 -0
  4. package/README.md +11 -0
  5. package/back/protos/api.proto +3 -0
  6. package/deploy/kubernetes/README.md +81 -0
  7. package/deploy/kubernetes/base/kustomization.yaml +5 -0
  8. package/deploy/kubernetes/base/qinglong.yaml +95 -0
  9. package/deploy/kubernetes/overlays/example/kustomization.yaml +10 -0
  10. package/docker/Dockerfile +51 -69
  11. package/docker/Dockerfile.310 +94 -0
  12. package/docker/Dockerfile.debian +120 -0
  13. package/docker/{310.Dockerfile → Dockerfile.debian310} +13 -5
  14. package/docker/docker-entrypoint.sh +95 -3
  15. package/docs/PROJECT_ARCHITECTURE.md +550 -0
  16. package/package.json +29 -28
  17. package/sample/config.sample.sh +19 -3
  18. package/sample/notify.js +145 -9
  19. package/sample/notify.py +110 -11
  20. package/shell/api.sh +51 -21
  21. package/shell/bot.sh +30 -16
  22. package/shell/check.sh +21 -19
  23. package/shell/lang/en.sh +105 -0
  24. package/shell/lang/zh.sh +105 -0
  25. package/shell/otask.sh +117 -28
  26. package/shell/preload/client.js +20 -2
  27. package/shell/preload/esm-loader.mjs +41 -0
  28. package/shell/preload/sitecustomize.js +36 -0
  29. package/shell/pub.sh +8 -8
  30. package/shell/rmlog.sh +5 -5
  31. package/shell/share.sh +50 -31
  32. package/shell/start.sh +40 -27
  33. package/shell/task.sh +10 -2
  34. package/shell/update.sh +22 -22
  35. package/static/build/api/config.js +17 -7
  36. package/static/build/api/cron.js +40 -3
  37. package/static/build/api/dashboard.js +344 -0
  38. package/static/build/api/env.js +40 -2
  39. package/static/build/api/index.js +2 -0
  40. package/static/build/api/log.js +15 -5
  41. package/static/build/api/script.js +34 -9
  42. package/static/build/api/system.js +22 -8
  43. package/static/build/api/user.js +6 -5
  44. package/static/build/app.js +22 -19
  45. package/static/build/config/const.js +8 -6
  46. package/static/build/config/container.js +12 -0
  47. package/static/build/config/grpcCerts.js +150 -0
  48. package/static/build/config/index.js +6 -4
  49. package/static/build/config/util.js +69 -18
  50. package/static/build/data/cron.js +3 -1
  51. package/static/build/data/cronStats.js +59 -0
  52. package/static/build/data/env.js +2 -0
  53. package/static/build/data/notify.js +18 -1
  54. package/static/build/data/runningInstance.js +57 -0
  55. package/static/build/data/sock.js +1 -0
  56. package/static/build/loaders/app.js +7 -7
  57. package/static/build/loaders/db.js +8 -2
  58. package/static/build/loaders/deps.js +1 -22
  59. package/static/build/loaders/express.js +19 -15
  60. package/static/build/loaders/initData.js +20 -2
  61. package/static/build/loaders/initFile.js +3 -1
  62. package/static/build/loaders/initTask.js +3 -2
  63. package/static/build/loaders/server.js +1 -1
  64. package/static/build/protos/api.js +23 -1
  65. package/static/build/schedule/addCron.js +67 -10
  66. package/static/build/schedule/api.js +1 -1
  67. package/static/build/schedule/client.js +9 -1
  68. package/static/build/schedule/delCron.js +11 -1
  69. package/static/build/schedule/health.js +1 -1
  70. package/static/build/services/config.js +19 -5
  71. package/static/build/services/cron.js +198 -38
  72. package/static/build/services/dependence.js +19 -18
  73. package/static/build/services/env.js +31 -3
  74. package/static/build/services/grpc.js +32 -6
  75. package/static/build/services/http.js +33 -18
  76. package/static/build/services/notify.js +87 -8
  77. package/static/build/services/open.js +2 -1
  78. package/static/build/services/sshKey.js +6 -3
  79. package/static/build/services/subscription.js +8 -5
  80. package/static/build/services/system.js +34 -9
  81. package/static/build/services/user.js +39 -13
  82. package/static/build/shared/auth.js +7 -1
  83. package/static/build/shared/i18n.js +160 -0
  84. package/static/build/shared/pLimit.js +15 -3
  85. package/static/build/shared/runCron.js +5 -0
  86. package/static/build/shared/store.js +7 -0
  87. package/static/build/validation/schedule.js +10 -0
  88. package/static/dist/1089.0ecc5383.async.js +1 -0
  89. package/static/dist/1147.62793604.async.js +1 -0
  90. package/static/dist/1192.4e5740f2.async.js +1 -0
  91. package/static/dist/1214.c6469b53.async.js +1 -0
  92. package/static/dist/134.54df9e38.async.js +1 -0
  93. package/static/dist/1352.96a77e1d.async.js +1 -0
  94. package/static/dist/{1765.d8e002d7.async.js → 1765.5ac01a93.async.js} +1 -1
  95. package/static/dist/1836.f0b74cf1.async.js +1 -0
  96. package/static/dist/{1885.e0d00d2d.async.js → 1885.e1ea09f6.async.js} +1 -1
  97. package/static/dist/1967.3f3945d0.async.js +1 -0
  98. package/static/dist/{2096.383c1047.async.js → 2096.6d98fd12.async.js} +1 -1
  99. package/static/dist/2208.85285476.async.js +1 -0
  100. package/static/dist/2286.f371c743.async.js +1 -0
  101. package/static/dist/2476.4e9b0992.async.js +1 -0
  102. package/static/dist/2537.2b262ee0.async.js +1 -0
  103. package/static/dist/{255.12f03ab2.async.js → 255.8a80b983.async.js} +1 -1
  104. package/static/dist/2635.d4c59d23.async.js +1 -0
  105. package/static/dist/2808.cdc0995c.async.js +1 -0
  106. package/static/dist/{2821.be3dc88e.async.js → 2821.651f31e5.async.js} +1 -1
  107. package/static/dist/2986.4c49eef7.async.js +1 -0
  108. package/static/dist/300.08ac9875.async.js +1 -0
  109. package/static/dist/3191.545ab873.async.js +1 -0
  110. package/static/dist/3714.8d6dba9e.async.js +1 -0
  111. package/static/dist/3906.a5eee612.async.js +1 -0
  112. package/static/dist/{6541.a6d499de.async.js → 3948.4fe809fd.async.js} +1 -1
  113. package/static/dist/{5171.7fc6d0a2.async.js → 4573.16f19278.async.js} +1 -1
  114. package/static/dist/{4859.93e63ea6.async.js → 4859.6592cebb.async.js} +1 -1
  115. package/static/dist/4887.8e3ae573.async.js +1 -0
  116. package/static/dist/{4902.54ecbdb5.async.js → 4902.555f92ab.async.js} +1 -1
  117. package/static/dist/{4934.1ca6b6b0.async.js → 4934.f3539d08.async.js} +1 -1
  118. package/static/dist/5077.cbd111cd.async.js +1 -0
  119. package/static/dist/{6247.b550d996.async.js → 5157.7c5af144.async.js} +1 -1
  120. package/static/dist/{540.481d4708.async.js → 540.19ddf020.async.js} +1 -1
  121. package/static/dist/{5970.10ac4f16.async.js → 5970.d3a6e7bd.async.js} +1 -1
  122. package/static/dist/{6013.2d7bb12a.async.js → 6013.4e38de36.async.js} +1 -1
  123. package/static/dist/{6016.9c379049.async.js → 6016.1e6574b6.async.js} +1 -1
  124. package/static/dist/{6035.5889ddc7.async.js → 6035.32ebfad9.async.js} +1 -1
  125. package/static/dist/6339.ab305e96.async.js +1 -0
  126. package/static/dist/6569.55177f6a.async.js +1 -0
  127. package/static/dist/6610.c111af7e.async.js +1 -0
  128. package/static/dist/{3034.6413c38e.async.js → 6638.87a163d2.async.js} +1 -1
  129. package/static/dist/{6646.5fc37228.async.js → 6646.95e92533.async.js} +1 -1
  130. package/static/dist/6665.1d099ad1.async.js +1 -0
  131. package/static/dist/{7355.b7c0562f.async.js → 7355.f9f263d8.async.js} +1 -1
  132. package/static/dist/{7384.065ccae2.async.js → 7384.1bb449d5.async.js} +1 -1
  133. package/static/dist/7441.ee1bf2bb.async.js +1 -0
  134. package/static/dist/{7508.a31662a3.async.js → 7508.7dcee91c.async.js} +1 -1
  135. package/static/dist/{7802.6b73f16a.async.js → 7802.34255805.async.js} +1 -1
  136. package/static/dist/{7984.e6bb9378.async.js → 7984.594296a5.async.js} +1 -1
  137. package/static/dist/{5653.4fce7ce8.async.js → 8033.5cb31493.async.js} +1 -1
  138. package/static/dist/8147.2fb55202.async.js +1 -0
  139. package/static/dist/8187.48c130d6.async.js +1 -0
  140. package/static/dist/8495.d53e15ca.async.js +1 -0
  141. package/static/dist/8587.315b06c0.async.js +1 -0
  142. package/static/dist/8826.db34ad8d.async.js +1 -0
  143. package/static/dist/{2742.4852aac8.async.js → 8865.ed665d31.async.js} +1 -1
  144. package/static/dist/901.7ee5c6d3.async.js +1 -0
  145. package/static/dist/9271.231db2ce.async.js +1 -0
  146. package/static/dist/9323.a33f47da.async.js +1 -0
  147. package/static/dist/{9730.30083c91.async.js → 9730.801665a3.async.js} +1 -1
  148. package/static/dist/{9761.627ca3b5.async.js → 9761.360a19d8.async.js} +1 -1
  149. package/static/dist/index.html +2 -2
  150. package/static/dist/layouts__index.a7a2bfe0.async.js +1 -0
  151. package/static/dist/layouts__index.adf0692f.chunk.css +1 -0
  152. package/static/dist/preload_helper.3048fe5b.js +1 -0
  153. package/static/dist/{src__pages__config__index.622b6ee8.async.js → src__pages__config__index.a22ff7dc.async.js} +1 -1
  154. package/static/dist/{src__pages__crontab__const.323d5124.async.js → src__pages__crontab__const.aba07deb.async.js} +1 -1
  155. package/static/dist/src__pages__crontab__detail.b98f0084.async.js +1 -0
  156. package/static/dist/src__pages__crontab__index.68e78a33.async.js +1 -0
  157. package/static/dist/{src__pages__crontab__logModal.5e6a4bf2.async.js → src__pages__crontab__logModal.831d5e4b.async.js} +1 -1
  158. package/static/dist/src__pages__crontab__modal.f7041c7c.async.js +1 -0
  159. package/static/dist/src__pages__crontab__type.d7af36e5.async.js +1 -0
  160. package/static/dist/{src__pages__crontab__viewCreateModal.ffcf7a24.async.js → src__pages__crontab__viewCreateModal.4d589f66.async.js} +1 -1
  161. package/static/dist/{src__pages__crontab__viewManageModal.c2724575.async.js → src__pages__crontab__viewManageModal.0e317746.async.js} +1 -1
  162. package/static/dist/src__pages__dashboard__index.58177357.async.js +1 -0
  163. package/static/dist/src__pages__dependence__index.b7bbc795.async.js +1 -0
  164. package/static/dist/{src__pages__dependence__logModal.f123e2ac.async.js → src__pages__dependence__logModal.0681830b.async.js} +1 -1
  165. package/static/dist/src__pages__dependence__modal.f7bb47ba.async.js +1 -0
  166. package/static/dist/src__pages__env__editNameModal.48715576.async.js +1 -0
  167. package/static/dist/src__pages__env__index.452cdc47.async.js +1 -0
  168. package/static/dist/src__pages__env__modal.e1234834.async.js +1 -0
  169. package/static/dist/src__pages__error__index.dedb2b90.async.js +1 -0
  170. package/static/dist/src__pages__initialization__index.22620a77.async.js +1 -0
  171. package/static/dist/src__pages__log__index.9c66639f.async.js +1 -0
  172. package/static/dist/{src__pages__login__index.cd6e3152.async.js → src__pages__login__index.8c813eb1.async.js} +1 -1
  173. package/static/dist/{src__pages__script__components__UnsupportedFilePreview__index.39074c68.async.js → src__pages__script__components__UnsupportedFilePreview__index.c347a13a.async.js} +1 -1
  174. package/static/dist/src__pages__script__editNameModal.532a3044.async.js +1 -0
  175. package/static/dist/src__pages__script__index.1fc20f22.async.js +1 -0
  176. package/static/dist/src__pages__script__renameModal.5cdde919.async.js +1 -0
  177. package/static/dist/src__pages__script__saveModal.5ffed35f.async.js +1 -0
  178. package/static/dist/src__pages__script__setting.1a82c6d7.async.js +1 -0
  179. package/static/dist/src__pages__setting__appModal.43b7758a.async.js +1 -0
  180. package/static/dist/src__pages__setting__checkUpdate.34d773f2.async.js +1 -0
  181. package/static/dist/src__pages__setting__dependence.9c04c79a.async.js +1 -0
  182. package/static/dist/src__pages__setting__index.7e070838.async.js +1 -0
  183. package/static/dist/src__pages__setting__notification.bac481c2.async.js +1 -0
  184. package/static/dist/src__pages__setting__other.707cfafe.async.js +1 -0
  185. package/static/dist/src__pages__setting__security.b7235753.async.js +1 -0
  186. package/static/dist/src__pages__setting__systemLog.b81a8c1d.async.js +1 -0
  187. package/static/dist/{src__pages__subscription__logModal.0caa7283.async.js → src__pages__subscription__logModal.3864b37f.async.js} +1 -1
  188. package/static/dist/src__pages__subscription__modal.562448e2.async.js +1 -0
  189. package/static/dist/{umi.ef8199a4.js → umi.a54a59f6.js} +1 -1
  190. package/version.yaml +33 -4
  191. package/sample/notify.py.save +0 -1010
  192. package/static/dist/105.85a5c47a.async.js +0 -1
  193. package/static/dist/1083.f86ce804.async.js +0 -1
  194. package/static/dist/1147.32f41a88.async.js +0 -1
  195. package/static/dist/1352.ab6da08e.async.js +0 -1
  196. package/static/dist/1690.f0290540.async.js +0 -1
  197. package/static/dist/1742.6cbe5aca.async.js +0 -1
  198. package/static/dist/2208.8e3a7325.async.js +0 -1
  199. package/static/dist/3191.70bc19db.async.js +0 -1
  200. package/static/dist/5312.74b95311.async.js +0 -1
  201. package/static/dist/5691.931f59c5.async.js +0 -1
  202. package/static/dist/6159.55cb068a.async.js +0 -1
  203. package/static/dist/7025.f4080d63.async.js +0 -1
  204. package/static/dist/739.6be5552a.async.js +0 -1
  205. package/static/dist/7571.4f6240b1.async.js +0 -1
  206. package/static/dist/786.59fc381c.async.js +0 -1
  207. package/static/dist/8317.c44c1ebd.async.js +0 -1
  208. package/static/dist/8826.0291edfd.async.js +0 -1
  209. package/static/dist/955.3c9481f7.async.js +0 -1
  210. package/static/dist/layouts__index.1fce90e0.chunk.css +0 -1
  211. package/static/dist/layouts__index.8dcf1576.async.js +0 -1
  212. package/static/dist/preload_helper.116a62f6.js +0 -1
  213. package/static/dist/src__pages__crontab__detail.b07f0c0a.async.js +0 -1
  214. package/static/dist/src__pages__crontab__index.2e2e1096.async.js +0 -1
  215. package/static/dist/src__pages__crontab__modal.4d8c2a22.async.js +0 -1
  216. package/static/dist/src__pages__crontab__type.db7c1858.async.js +0 -1
  217. package/static/dist/src__pages__dependence__index.3d87ceac.async.js +0 -1
  218. package/static/dist/src__pages__dependence__modal.631ffb5b.async.js +0 -1
  219. package/static/dist/src__pages__env__editNameModal.ff85ef8c.async.js +0 -1
  220. package/static/dist/src__pages__env__index.a0a2fece.async.js +0 -1
  221. package/static/dist/src__pages__env__modal.d1004662.async.js +0 -1
  222. package/static/dist/src__pages__error__index.1bc3c90b.async.js +0 -1
  223. package/static/dist/src__pages__initialization__index.8b1cbaf9.async.js +0 -1
  224. package/static/dist/src__pages__log__index.cf00c9af.async.js +0 -1
  225. package/static/dist/src__pages__script__editNameModal.53424d49.async.js +0 -1
  226. package/static/dist/src__pages__script__index.e65df827.async.js +0 -1
  227. package/static/dist/src__pages__script__renameModal.4bbe7fb1.async.js +0 -1
  228. package/static/dist/src__pages__script__saveModal.cf449f3c.async.js +0 -1
  229. package/static/dist/src__pages__script__setting.b345d59a.async.js +0 -1
  230. package/static/dist/src__pages__setting__appModal.03faec89.async.js +0 -1
  231. package/static/dist/src__pages__setting__checkUpdate.46efe057.async.js +0 -1
  232. package/static/dist/src__pages__setting__dependence.4495c7b6.async.js +0 -1
  233. package/static/dist/src__pages__setting__index.6919c399.async.js +0 -1
  234. package/static/dist/src__pages__setting__notification.d6a3884f.async.js +0 -1
  235. package/static/dist/src__pages__setting__other.0d931d6f.async.js +0 -1
  236. package/static/dist/src__pages__setting__security.91cb545f.async.js +0 -1
  237. package/static/dist/src__pages__setting__systemLog.1d433a48.async.js +0 -1
  238. package/static/dist/src__pages__subscription__modal.0b84f6cf.async.js +0 -1
@@ -13,31 +13,46 @@ exports.HttpServerService = void 0;
13
13
  const logger_1 = __importDefault(require("../loaders/logger"));
14
14
  const metrics_1 = require("./metrics");
15
15
  const typedi_1 = require("typedi");
16
+ const config_1 = __importDefault(require("../config"));
16
17
  let HttpServerService = class HttpServerService {
17
18
  constructor() {
18
19
  this.server = undefined;
19
20
  }
20
21
  async initialize(expressApp, port) {
21
- try {
22
- return new Promise((resolve, reject) => {
23
- var _a;
24
- this.server = expressApp.listen(port, '0.0.0.0', () => {
25
- logger_1.default.debug(`✌️ HTTP service started successfully`);
26
- metrics_1.metricsService.record('http_service_start', 1, {
27
- port: port.toString(),
28
- });
29
- resolve(this.server);
30
- });
31
- (_a = this.server) === null || _a === void 0 ? void 0 : _a.on('error', (err) => {
32
- logger_1.default.error('Failed to start HTTP service:', err);
33
- reject(err);
22
+ const hostsToTry = [
23
+ config_1.default.bindHost,
24
+ ...(config_1.default.bindHost !== '0.0.0.0' ? ['0.0.0.0'] : [])
25
+ ];
26
+ let lastError = null;
27
+ for (const host of hostsToTry) {
28
+ try {
29
+ const server = await this.tryListen(expressApp, port, host);
30
+ logger_1.default.debug(`[boot] HTTP service started successfully on ${host}:${port}`);
31
+ metrics_1.metricsService.record('http_service_start', 1, {
32
+ port: port.toString(),
33
+ host
34
34
  });
35
- });
36
- }
37
- catch (err) {
38
- logger_1.default.error('Failed to start HTTP service:', err);
39
- throw err;
35
+ this.server = server;
36
+ return server;
37
+ }
38
+ catch (err) {
39
+ lastError = err;
40
+ logger_1.default.warn(`Failed to bind HTTP on ${host}:${port}, trying next...`, err);
41
+ }
40
42
  }
43
+ logger_1.default.error('Failed to start HTTP service on all hosts');
44
+ throw lastError || new Error('Failed to start HTTP service');
45
+ }
46
+ async tryListen(expressApp, port, host) {
47
+ return new Promise((resolve, reject) => {
48
+ const server = expressApp.listen(port, host, () => {
49
+ resolve(server);
50
+ });
51
+ server.on('error', (err) => {
52
+ server.close();
53
+ reject(err);
54
+ });
55
+ });
41
56
  }
42
57
  async shutdown() {
43
58
  try {
@@ -27,6 +27,7 @@ const crypto_1 = __importDefault(require("crypto"));
27
27
  const nodemailer_1 = __importDefault(require("nodemailer"));
28
28
  const typedi_1 = require("typedi");
29
29
  const util_1 = require("../config/util");
30
+ const i18n_1 = require("../shared/i18n");
30
31
  const user_1 = __importDefault(require("./user"));
31
32
  const http_1 = require("../config/http");
32
33
  const undici_1 = require("undici");
@@ -54,6 +55,8 @@ let NotificationService = class NotificationService {
54
55
  ['chronocat', this.chronocat],
55
56
  ['ntfy', this.ntfy],
56
57
  ['wxPusherBot', this.wxPusherBot],
58
+ ['wxPusherSpt', this.wxPusherSpt],
59
+ ['openiLink', this.openiLink],
57
60
  ]);
58
61
  this.title = '';
59
62
  this.content = '';
@@ -97,6 +100,13 @@ let NotificationService = class NotificationService {
97
100
  }
98
101
  return true;
99
102
  }
103
+ parseMailRecipients(value) {
104
+ const recipients = (value || '')
105
+ .split(/[;;]/)
106
+ .map((item) => item.trim())
107
+ .filter(Boolean);
108
+ return recipients.length > 0 ? recipients : undefined;
109
+ }
100
110
  async gotify() {
101
111
  const { gotifyUrl, gotifyToken, gotifyPriority = 1 } = this.params;
102
112
  try {
@@ -297,7 +307,7 @@ let NotificationService = class NotificationService {
297
307
  {
298
308
  title: `${this.title}`,
299
309
  thumb_media_id,
300
- author: `智能助手`,
310
+ author: (0, i18n_1.t)('智能助手'),
301
311
  content_source_url: ``,
302
312
  content: `${this.content.replace(/\n/g, '<br/>')}`,
303
313
  digest: `${this.content}`,
@@ -313,7 +323,7 @@ let NotificationService = class NotificationService {
313
323
  title: `${this.title}`,
314
324
  description: `${this.content}`,
315
325
  url: 'https://github.com/whyour/qinglong',
316
- btntxt: '更多',
326
+ btntxt: (0, i18n_1.t)('更多'),
317
327
  },
318
328
  };
319
329
  break;
@@ -352,7 +362,7 @@ let NotificationService = class NotificationService {
352
362
  roomName: `${aibotkName}`,
353
363
  message: {
354
364
  type: 1,
355
- content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
365
+ content: `【${(0, i18n_1.t)('青龙快讯')}】\n\n${this.title}\n${this.content}`,
356
366
  },
357
367
  };
358
368
  break;
@@ -363,7 +373,7 @@ let NotificationService = class NotificationService {
363
373
  name: `${aibotkName}`,
364
374
  message: {
365
375
  type: 1,
366
- content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
376
+ content: `【${(0, i18n_1.t)('青龙快讯')}】\n\n${this.title}\n${this.content}`,
367
377
  },
368
378
  };
369
379
  break;
@@ -488,6 +498,7 @@ let NotificationService = class NotificationService {
488
498
  }
489
499
  async email() {
490
500
  const { emailPass, emailService, emailUser, emailTo } = this.params;
501
+ const recipients = this.parseMailRecipients(emailTo) || emailUser;
491
502
  try {
492
503
  const transporter = nodemailer_1.default.createTransport({
493
504
  service: emailService,
@@ -497,8 +508,8 @@ let NotificationService = class NotificationService {
497
508
  },
498
509
  });
499
510
  const info = await transporter.sendMail({
500
- from: `"青龙快讯" <${emailUser}>`,
501
- to: emailTo ? emailTo.split(';') : emailUser,
511
+ from: `"${(0, i18n_1.t)('青龙快讯')}" <${emailUser}>`,
512
+ to: recipients,
502
513
  subject: `${this.title}`,
503
514
  html: `${this.content.replace(/\n/g, '<br/>')}`,
504
515
  });
@@ -586,7 +597,7 @@ let NotificationService = class NotificationService {
586
597
  : [];
587
598
  // topic_ids 和 uids 至少要有一个
588
599
  if (!topicIds.length && !uids.length) {
589
- throw new Error('wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行');
600
+ throw new Error((0, i18n_1.t)('wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行'));
590
601
  }
591
602
  const url = `https://wxpusher.zjiecode.com/api/send/message`;
592
603
  try {
@@ -610,6 +621,47 @@ let NotificationService = class NotificationService {
610
621
  throw new Error(error.response ? error.response.body : error);
611
622
  }
612
623
  }
624
+ async wxPusherSpt() {
625
+ const { wxPusherSptList } = this.params;
626
+ // 处理 SPT,将逗号分隔的字符串转为数组
627
+ const spts = wxPusherSptList
628
+ ? wxPusherSptList
629
+ .split(',')
630
+ .map((spt) => spt.trim())
631
+ .filter((spt) => spt)
632
+ : [];
633
+ if (!spts.length) {
634
+ throw new Error((0, i18n_1.t)('wxPusher SPT 不能为空'));
635
+ }
636
+ if (spts.length > 10) {
637
+ throw new Error((0, i18n_1.t)('wxPusher SPT 最多支持 10 个'));
638
+ }
639
+ const url = `https://wxpusher.zjiecode.com/api/send/message/simple-push`;
640
+ const json = {
641
+ content: `<h1>${this.title}</h1><br/><div style='white-space: pre-wrap;'>${this.content}</div>`,
642
+ summary: this.title,
643
+ contentType: 2,
644
+ };
645
+ // 单个 SPT 用 spt,多个用 sptList
646
+ if (spts.length === 1) {
647
+ json.spt = spts[0];
648
+ }
649
+ else {
650
+ json.sptList = spts;
651
+ }
652
+ try {
653
+ const res = await http_1.httpClient.post(url, Object.assign(Object.assign({}, this.gotOption), { json }));
654
+ if (res.code === 1000) {
655
+ return true;
656
+ }
657
+ else {
658
+ throw new Error(JSON.stringify(res));
659
+ }
660
+ }
661
+ catch (error) {
662
+ throw new Error(error.response ? error.response.body : error);
663
+ }
664
+ }
613
665
  async chronocat() {
614
666
  var _a, _b;
615
667
  const { chronocatURL, chronocatQQ, chronocatToken } = this.params;
@@ -665,7 +717,7 @@ let NotificationService = class NotificationService {
665
717
  var _a;
666
718
  const { webhookUrl, webhookBody, webhookHeaders, webhookMethod, webhookContentType, } = this.params;
667
719
  if (!(webhookUrl === null || webhookUrl === void 0 ? void 0 : webhookUrl.includes('$title')) && !(webhookBody === null || webhookBody === void 0 ? void 0 : webhookBody.includes('$title'))) {
668
- throw new Error('Url 或者 Body 中必须包含 $title');
720
+ throw new Error((0, i18n_1.t)('Url 或者 Body 中必须包含 $title'));
669
721
  }
670
722
  const headers = (0, util_1.parseHeaders)(webhookHeaders);
671
723
  const body = (0, util_1.parseBody)(webhookBody, webhookContentType, (v) => { var _a; return (_a = v === null || v === void 0 ? void 0 : v.replaceAll('$title', this.title)) === null || _a === void 0 ? void 0 : _a.replaceAll('$content', this.content); });
@@ -700,6 +752,33 @@ let NotificationService = class NotificationService {
700
752
  }
701
753
  return {};
702
754
  }
755
+ async openiLink() {
756
+ const { openiLinkAppToken, openiLinkHubUrl, openiLinkContextToken } = this.params;
757
+ const baseUrl = (openiLinkHubUrl === null || openiLinkHubUrl === void 0 ? void 0 : openiLinkHubUrl.replace(/\/$/, '')) || 'https://hub.openilink.com';
758
+ const url = `${baseUrl}/bot/v1/message/send`;
759
+ const body = {
760
+ type: 'text',
761
+ content: `${this.title}\n\n${this.content}`,
762
+ };
763
+ if (openiLinkContextToken) {
764
+ body.context_token = openiLinkContextToken;
765
+ }
766
+ try {
767
+ const res = await http_1.httpClient.post(url, Object.assign(Object.assign({}, this.gotOption), { json: body, headers: {
768
+ 'Content-Type': 'application/json',
769
+ Authorization: `Bearer ${openiLinkAppToken}`,
770
+ } }));
771
+ if (res.ok) {
772
+ return true;
773
+ }
774
+ else {
775
+ throw new Error(JSON.stringify(res));
776
+ }
777
+ }
778
+ catch (error) {
779
+ throw new Error(error.response ? error.response.body : error);
780
+ }
781
+ }
703
782
  };
704
783
  __decorate([
705
784
  (0, typedi_1.Inject)((type) => user_1.default),
@@ -22,6 +22,7 @@ const open_1 = require("../data/open");
22
22
  const uuid_1 = require("uuid");
23
23
  const sequelize_1 = require("sequelize");
24
24
  const store_1 = require("../shared/store");
25
+ const i18n_1 = require("../shared/i18n");
25
26
  let OpenService = class OpenService {
26
27
  constructor(logger) {
27
28
  this.logger = logger;
@@ -141,7 +142,7 @@ let OpenService = class OpenService {
141
142
  };
142
143
  }
143
144
  else {
144
- return { code: 400, message: 'client_id 或 client_seret 有误' };
145
+ return { code: 400, message: (0, i18n_1.t)('client_id 或 client_seret 有误') };
145
146
  }
146
147
  }
147
148
  async generateSystemToken() {
@@ -48,9 +48,12 @@ let SshKeyService = class SshKeyService {
48
48
  }
49
49
  async generatePrivateKeyFile(alias, key) {
50
50
  try {
51
- await (0, utils_1.writeFileWithLock)(path_1.default.join(this.sshPath, alias), `${key}${os_1.default.EOL}`, {
52
- mode: '400',
53
- });
51
+ const filePath = path_1.default.join(this.sshPath, alias);
52
+ try {
53
+ await (0, util_1.rmPath)(filePath);
54
+ }
55
+ catch (_a) { }
56
+ await (0, utils_1.writeFileWithLock)(filePath, `${key}${os_1.default.EOL}`, { mode: '400' });
54
57
  }
55
58
  catch (error) {
56
59
  this.logger.error('生成私钥文件失败', error);
@@ -48,6 +48,7 @@ const sequelize_1 = require("sequelize");
48
48
  const path_1 = __importStar(require("path"));
49
49
  const schedule_1 = __importDefault(require("./schedule"));
50
50
  const sock_1 = __importDefault(require("./sock"));
51
+ const i18n_1 = require("../shared/i18n");
51
52
  const sshKey_1 = __importDefault(require("./sshKey"));
52
53
  const const_1 = require("../config/const");
53
54
  const subscription_2 = require("../config/subscription");
@@ -125,12 +126,12 @@ let SubscriptionService = class SubscriptionService {
125
126
  status: subscription_1.SubscriptionStatus.running,
126
127
  log_path: logPath,
127
128
  }, { where: { id: doc.id } });
128
- const absolutePath = await (0, util_1.handleLogPath)(logPath, `## 开始执行... ${startTime.format('YYYY-MM-DD HH:mm:ss')}\n`);
129
+ const absolutePath = await (0, util_1.handleLogPath)(logPath, (0, i18n_1.tf)('## 开始执行... %s\n', startTime.format('YYYY-MM-DD HH:mm:ss')));
129
130
  // 执行sub_before
130
131
  let beforeStr = '';
131
132
  try {
132
133
  if (doc.sub_before) {
133
- await logStreamManager_1.logStreamManager.write(absolutePath, `\n## 执行before命令...\n\n`);
134
+ await logStreamManager_1.logStreamManager.write(absolutePath, `\n## ${(0, i18n_1.t)('执行before命令...')}\n\n`);
134
135
  beforeStr = await (0, util_1.promiseExec)(doc.sub_before);
135
136
  }
136
137
  }
@@ -154,7 +155,7 @@ let SubscriptionService = class SubscriptionService {
154
155
  let afterStr = '';
155
156
  try {
156
157
  if (sub.sub_after) {
157
- await logStreamManager_1.logStreamManager.write(absolutePath, `\n\n## 执行after命令...\n\n`);
158
+ await logStreamManager_1.logStreamManager.write(absolutePath, `\n\n## ${(0, i18n_1.t)('执行after命令...')}\n\n`);
158
159
  afterStr = await (0, util_1.promiseExec)(sub.sub_after);
159
160
  }
160
161
  }
@@ -165,13 +166,15 @@ let SubscriptionService = class SubscriptionService {
165
166
  if (afterStr) {
166
167
  await logStreamManager_1.logStreamManager.write(absolutePath, `${afterStr}\n`);
167
168
  }
168
- await logStreamManager_1.logStreamManager.write(absolutePath, `\n## 执行结束... ${endTime.format('YYYY-MM-DD HH:mm:ss')} 耗时 ${diff} 秒${const_1.LOG_END_SYMBOL}`);
169
+ await logStreamManager_1.logStreamManager.write(absolutePath, '\n' +
170
+ (0, i18n_1.tf)('## 执行结束... %s 耗时 %s 秒', endTime.format('YYYY-MM-DD HH:mm:ss'), String(diff)) +
171
+ const_1.LOG_END_SYMBOL);
169
172
  // Close the stream after task completion
170
173
  await logStreamManager_1.logStreamManager.closeStream(absolutePath);
171
174
  await subscription_1.SubscriptionModel.update({ status: subscription_1.SubscriptionStatus.idle, pid: undefined }, { where: { id: sub.id } });
172
175
  this.sockService.sendMessage({
173
176
  type: 'runSubscriptionEnd',
174
- message: '订阅执行完成',
177
+ message: (0, i18n_1.t)('订阅执行完成'),
175
178
  references: [doc.id],
176
179
  });
177
180
  },
@@ -44,6 +44,7 @@ const schedule_1 = __importDefault(require("./schedule"));
44
44
  const sock_1 = __importDefault(require("./sock"));
45
45
  const os_1 = __importDefault(require("os"));
46
46
  const dayjs_1 = __importDefault(require("dayjs"));
47
+ const i18n_1 = require("../shared/i18n");
47
48
  const util_2 = require("../config/util");
48
49
  let SystemService = class SystemService {
49
50
  constructor(logger, scheduleService, sockService) {
@@ -71,7 +72,7 @@ let SystemService = class SystemService {
71
72
  }
72
73
  async updateNotificationMode(notificationInfo) {
73
74
  const code = Math.random().toString().slice(-6);
74
- const isSuccess = await this.notificationService.testNotify(notificationInfo, '青龙', `【蛟龙】测试通知 https://t.me/jiao_long`);
75
+ const isSuccess = await this.notificationService.testNotify(notificationInfo, (0, i18n_1.t)('青龙'), (0, i18n_1.t)('【蛟龙】测试通知 https://t.me/jiao_long'));
75
76
  if (isSuccess) {
76
77
  const result = await this.updateAuthDb({
77
78
  type: system_1.AuthDataType.notification,
@@ -80,7 +81,7 @@ let SystemService = class SystemService {
80
81
  return { code: 200, data: Object.assign(Object.assign({}, result), { code }) };
81
82
  }
82
83
  else {
83
- return { code: 400, message: '通知发送失败,请检查参数' };
84
+ return { code: 400, message: (0, i18n_1.t)('通知发送失败,请检查参数') };
84
85
  }
85
86
  }
86
87
  async updateLogRemoveFrequency(info) {
@@ -89,7 +90,7 @@ let SystemService = class SystemService {
89
90
  const result = await this.updateAuthDb(Object.assign(Object.assign({}, oDoc), { info: Object.assign(Object.assign({}, oDoc.info), info) }));
90
91
  const cron = {
91
92
  id: result.id,
92
- name: '删除日志',
93
+ name: (0, i18n_1.t)('删除日志'),
93
94
  command: `ql rmlog ${info.logRemoveFrequency}`,
94
95
  runOrigin: 'system',
95
96
  };
@@ -148,6 +149,7 @@ let SystemService = class SystemService {
148
149
  this.sockService.sendMessage({
149
150
  type: 'updateNodeMirror',
150
151
  message: 'update node mirror end',
152
+ status: 'completed',
151
153
  });
152
154
  },
153
155
  onError: async (message) => {
@@ -188,6 +190,7 @@ let SystemService = class SystemService {
188
190
  this.sockService.sendMessage({
189
191
  type: 'updateLinuxMirror',
190
192
  message: 'update linux mirror end',
193
+ status: 'completed',
191
194
  });
192
195
  onEnd === null || onEnd === void 0 ? void 0 : onEnd();
193
196
  if (!hasError) {
@@ -276,6 +279,14 @@ let SystemService = class SystemService {
276
279
  this.sockService.sendMessage({
277
280
  type: 'updateSystemVersion',
278
281
  message: JSON.stringify(err),
282
+ status: 'failed',
283
+ });
284
+ });
285
+ cp.on('exit', (code) => {
286
+ this.sockService.sendMessage({
287
+ type: 'updateSystemVersion',
288
+ message: '',
289
+ status: code === 0 ? 'success' : 'failed',
279
290
  });
280
291
  });
281
292
  return { code: 200 };
@@ -302,10 +313,10 @@ let SystemService = class SystemService {
302
313
  }
303
314
  const isSuccess = await this.notificationService.notify(title, content, notificationInfo);
304
315
  if (isSuccess) {
305
- return { code: 200, message: '通知发送成功' };
316
+ return { code: 200, message: (0, i18n_1.t)('通知发送成功') };
306
317
  }
307
318
  else {
308
- return { code: 400, message: '通知发送失败,请检查系统设置/通知配置' };
319
+ return { code: 400, message: (0, i18n_1.t)('通知发送失败,请检查系统设置/通知配置') };
309
320
  }
310
321
  }
311
322
  async run({ command, logPath }, callback) {
@@ -321,7 +332,7 @@ let SystemService = class SystemService {
321
332
  }
322
333
  async stop({ command, pid }) {
323
334
  if (!pid && !command) {
324
- return { code: 400, message: '参数错误' };
335
+ return { code: 400, message: (0, i18n_1.t)('参数错误') };
325
336
  }
326
337
  if (pid) {
327
338
  await (0, util_1.killTask)(pid);
@@ -336,7 +347,7 @@ let SystemService = class SystemService {
336
347
  return { code: 200 };
337
348
  }
338
349
  else {
339
- return { code: 400, message: '任务未找到' };
350
+ return { code: 400, message: (0, i18n_1.t)('任务未找到') };
340
351
  }
341
352
  }
342
353
  async exportData(res, type) {
@@ -411,8 +422,22 @@ let SystemService = class SystemService {
411
422
  return { code: 200, data: info };
412
423
  }
413
424
  else {
414
- return { code: 400, message: '设置时区失败' };
425
+ return { code: 400, message: (0, i18n_1.t)('设置时区失败') };
426
+ }
427
+ }
428
+ async updateLanguage(info) {
429
+ const oDoc = await this.getSystemConfig();
430
+ const lang = info.lang || 'zh';
431
+ await this.updateAuthDb(Object.assign(Object.assign({}, oDoc), { info: Object.assign(Object.assign({}, oDoc.info), { lang }) }));
432
+ // Write to standalone lang_env.sh, sourced by shell scripts
433
+ try {
434
+ await fs_1.default.promises.writeFile(config_1.default.langEnvFile, `export QL_LANG='${lang}'\n`);
435
+ }
436
+ catch (error) {
437
+ this.logger.error(`Failed to write lang_env.sh: ${error}`);
415
438
  }
439
+ (0, i18n_1.setLang)(lang);
440
+ return { code: 200, data: { lang } };
416
441
  }
417
442
  async updateGlobalSshKey(info) {
418
443
  const oDoc = await this.getSystemConfig();
@@ -431,7 +456,7 @@ let SystemService = class SystemService {
431
456
  }
432
457
  async cleanDependence(type) {
433
458
  if (!type || !['node', 'python3'].includes(type)) {
434
- return { code: 400, message: '参数错误' };
459
+ return { code: 400, message: (0, i18n_1.t)('参数错误') };
435
460
  }
436
461
  try {
437
462
  const finalPath = path_1.default.join(config_1.default.dependenceCachePath, type);
@@ -32,6 +32,7 @@ const uniq_1 = __importDefault(require("lodash/uniq"));
32
32
  const pickBy_1 = __importDefault(require("lodash/pickBy"));
33
33
  const isNil_1 = __importDefault(require("lodash/isNil"));
34
34
  const store_1 = require("../shared/store");
35
+ const i18n_1 = require("../shared/i18n");
35
36
  let UserService = class UserService {
36
37
  constructor(logger, scheduleService, sockService) {
37
38
  this.logger = logger;
@@ -48,7 +49,7 @@ let UserService = class UserService {
48
49
  const waitTime = Math.ceil((retriesTime - (timestamp - lastlogon)) / 1000);
49
50
  return {
50
51
  code: 410,
51
- message: `失败次数过多,请${waitTime}秒后重试`,
52
+ message: (0, i18n_1.tf)('失败次数过多,请%s秒后重试', waitTime),
52
53
  data: waitTime,
53
54
  };
54
55
  }
@@ -97,7 +98,18 @@ let UserService = class UserService {
97
98
  platform: req.platform,
98
99
  isTwoFactorChecking: false,
99
100
  });
100
- this.notificationService.notify('登录通知', `你于${(0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss')}在 ${address} ${req.platform}端 登录成功,ip地址 ${ip}`);
101
+ this.notificationService.notify((0, i18n_1.t)('登录通知'), (0, i18n_1.t)('你于') +
102
+ (0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss') +
103
+ (0, i18n_1.t)('在') +
104
+ address +
105
+ ' ' +
106
+ req.platform +
107
+ (0, i18n_1.t)('端') +
108
+ ' ' +
109
+ (0, i18n_1.t)('登录成功') +
110
+ (0, i18n_1.t)(',ip地址') +
111
+ ' ' +
112
+ ip);
101
113
  await this.insertDb({
102
114
  type: system_1.AuthDataType.loginLog,
103
115
  info: {
@@ -129,7 +141,18 @@ let UserService = class UserService {
129
141
  lastaddr: address,
130
142
  platform: req.platform,
131
143
  });
132
- this.notificationService.notify('登录通知', `你于${(0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss')}在 ${address} ${req.platform}端 登录失败,ip地址 ${ip}`);
144
+ this.notificationService.notify((0, i18n_1.t)('登录通知'), (0, i18n_1.t)('你于') +
145
+ (0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss') +
146
+ (0, i18n_1.t)('在') +
147
+ address +
148
+ ' ' +
149
+ req.platform +
150
+ (0, i18n_1.t)('端') +
151
+ ' ' +
152
+ (0, i18n_1.t)('登录失败') +
153
+ (0, i18n_1.t)(',ip地址') +
154
+ ' ' +
155
+ ip);
133
156
  await this.insertDb({
134
157
  type: system_1.AuthDataType.loginLog,
135
158
  info: {
@@ -145,12 +168,12 @@ let UserService = class UserService {
145
168
  const waitTime = Math.round(Math.pow(3, retries + 1));
146
169
  return {
147
170
  code: 410,
148
- message: `失败次数过多,请${waitTime}秒后重试`,
171
+ message: (0, i18n_1.tf)('失败次数过多,请%s秒后重试', waitTime),
149
172
  data: waitTime,
150
173
  };
151
174
  }
152
175
  else {
153
- return { code: 400, message: config_1.default.authError };
176
+ return { code: 400, message: (0, i18n_1.t)('错误的用户名密码,请重试') };
154
177
  }
155
178
  }
156
179
  }
@@ -195,16 +218,16 @@ let UserService = class UserService {
195
218
  }
196
219
  async updateUsernameAndPassword({ username, password, }) {
197
220
  if (password === 'admin') {
198
- return { code: 400, message: '密码不能设置为admin' };
221
+ return { code: 400, message: (0, i18n_1.t)('密码不能设置为admin') };
199
222
  }
200
223
  const authInfo = await this.getAuthInfo();
201
224
  await this.updateAuthInfo(authInfo, { username, password });
202
- return { code: 200, message: '更新成功' };
225
+ return { code: 200, message: (0, i18n_1.t)('更新成功') };
203
226
  }
204
227
  async updateAvatar(avatar) {
205
228
  const authInfo = await this.getAuthInfo();
206
229
  await this.updateAuthInfo(authInfo, { avatar });
207
- return { code: 200, data: avatar, message: '更新成功' };
230
+ return { code: 200, data: avatar, message: (0, i18n_1.t)('更新成功') };
208
231
  }
209
232
  async initTwoFactor() {
210
233
  const secret = preset_default_1.authenticator.generateSecret();
@@ -228,7 +251,7 @@ let UserService = class UserService {
228
251
  const authInfo = await this.getAuthInfo();
229
252
  const { isTwoFactorChecking, twoFactorSecret } = authInfo;
230
253
  if (!isTwoFactorChecking) {
231
- return { code: 450, message: '未知错误' };
254
+ return { code: 450, message: (0, i18n_1.t)('未知错误') };
232
255
  }
233
256
  const isValid = preset_default_1.authenticator.verify({
234
257
  token: code,
@@ -253,10 +276,10 @@ let UserService = class UserService {
253
276
  lastaddr: address,
254
277
  platform: req.platform,
255
278
  });
256
- return { code: 430, message: '验证失败' };
279
+ return { code: 430, message: (0, i18n_1.t)('验证失败') };
257
280
  }
258
281
  }
259
- async deactiveTwoFactor() {
282
+ async deactivateTwoFactor() {
260
283
  const authInfo = await this.getAuthInfo();
261
284
  await this.updateAuthInfo(authInfo, {
262
285
  twoFactorActivated: false,
@@ -307,7 +330,7 @@ let UserService = class UserService {
307
330
  }
308
331
  async updateNotificationMode(notificationInfo) {
309
332
  const code = Math.random().toString().slice(-6);
310
- const isSuccess = await this.notificationService.testNotify(notificationInfo, '青龙', `【蛟龙】测试通知 https://t.me/jiao_long`);
333
+ const isSuccess = await this.notificationService.testNotify(notificationInfo, (0, i18n_1.t)('青龙'), (0, i18n_1.t)('【蛟龙】测试通知 https://t.me/jiao_long'));
311
334
  if (isSuccess) {
312
335
  const result = await this.updateAuthDb({
313
336
  type: system_1.AuthDataType.notification,
@@ -316,7 +339,7 @@ let UserService = class UserService {
316
339
  return { code: 200, data: Object.assign(Object.assign({}, result), { code }) };
317
340
  }
318
341
  else {
319
- return { code: 400, message: '通知发送失败,请检查参数' };
342
+ return { code: 400, message: (0, i18n_1.t)('通知发送失败,请检查参数') };
320
343
  }
321
344
  }
322
345
  normalizeTokens(tokens) {
@@ -380,6 +403,9 @@ let UserService = class UserService {
380
403
  }
381
404
  async resetAuthInfo(info) {
382
405
  const { retries, twoFactorActivated, password, username } = info;
406
+ if (password === 'admin') {
407
+ return { code: 400, message: (0, i18n_1.t)('密码不能设置为admin') };
408
+ }
383
409
  const authInfo = await this.getAuthInfo();
384
410
  const payload = (0, pickBy_1.default)({
385
411
  retries,
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isValidToken = void 0;
3
+ exports.isValidToken = exports.isDefaultAuthInfo = void 0;
4
+ function isDefaultAuthInfo(authInfo) {
5
+ return (Object.keys(authInfo).length === 2 &&
6
+ authInfo.username === 'admin' &&
7
+ authInfo.password === 'admin');
8
+ }
9
+ exports.isDefaultAuthInfo = isDefaultAuthInfo;
4
10
  /**
5
11
  * Validates if a token exists in the authentication info.
6
12
  * Supports both legacy string tokens and new TokenInfo array format.