@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
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@whyour/qinglong",
3
3
  "packageManager": "pnpm@8.3.1",
4
- "version": "2.20.2-3",
4
+ "version": "2.21.0-10",
5
5
  "description": "Timed task management platform supporting Python3, JavaScript, Shell, Typescript",
6
6
  "repository": {
7
7
  "type": "git",
@@ -21,9 +21,7 @@
21
21
  "panel": "npm run build:back && node static/build/app.js",
22
22
  "gen:proto": "protoc --experimental_allow_proto3_optional --plugin=./node_modules/.bin/protoc-gen-ts_proto ./back/protos/*.proto --ts_proto_out=./ --ts_proto_opt=outputServices=grpc-js,env=node,esModuleInterop=true,snakeToCamel=false",
23
23
  "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
24
- "postinstall": "max setup 2>/dev/null || true",
25
- "test": "umi-test",
26
- "test:coverage": "umi-test --coverage"
24
+ "postinstall": "max setup 2>/dev/null || true"
27
25
  },
28
26
  "gitHooks": {
29
27
  "pre-commit": "lint-staged"
@@ -67,16 +65,22 @@
67
65
  }
68
66
  },
69
67
  "overrides": {
70
- "sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3"
68
+ "sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3",
69
+ "@codemirror/state": "6.5.4",
70
+ "@codemirror/view": "6.39.16"
71
71
  }
72
72
  },
73
73
  "dependencies": {
74
+ "@ant-design/plots": "^2.6.8",
75
+ "@bufbuild/protobuf": "^2.10.0",
74
76
  "@grpc/grpc-js": "^1.14.0",
75
77
  "@grpc/proto-loader": "^0.8.0",
78
+ "@keyv/sqlite": "^4.0.1",
76
79
  "@otplib/preset-default": "^12.0.1",
77
80
  "body-parser": "^1.20.3",
78
81
  "celebrate": "^15.0.3",
79
82
  "chokidar": "^4.0.1",
83
+ "compression": "^1.7.4",
80
84
  "cors": "^2.8.5",
81
85
  "cron-parser": "^5.4.0",
82
86
  "cross-spawn": "^7.0.6",
@@ -86,51 +90,48 @@
86
90
  "express-jwt": "^8.4.1",
87
91
  "express-rate-limit": "^7.4.1",
88
92
  "express-urlrewrite": "^2.0.3",
89
- "undici": "^7.9.0",
93
+ "helmet": "^8.1.0",
90
94
  "hpagent": "^1.2.0",
91
95
  "http-proxy-middleware": "^3.0.3",
92
96
  "iconv-lite": "^0.6.3",
97
+ "ip2region": "2.3.0",
93
98
  "js-yaml": "^4.1.0",
94
99
  "jsonwebtoken": "^9.0.2",
100
+ "keyv": "^5.2.3",
95
101
  "lodash": "^4.17.21",
96
- "multer": "1.4.5-lts.1",
102
+ "multer": "2.1.1",
97
103
  "node-schedule": "^2.1.0",
98
- "nodemailer": "^6.9.16",
104
+ "nodemailer": "^8.0.1",
99
105
  "p-queue-cjs": "7.3.4",
100
- "@bufbuild/protobuf": "^2.10.0",
106
+ "proper-lockfile": "^4.1.2",
101
107
  "ps-tree": "^1.2.0",
102
108
  "reflect-metadata": "^0.2.2",
109
+ "request-ip": "3.3.0",
103
110
  "sequelize": "^6.37.5",
104
111
  "sockjs": "^0.3.24",
105
112
  "sqlite3": "git+https://github.com/whyour/node-sqlite3.git#v1.0.3",
106
113
  "toad-scheduler": "^3.0.1",
107
114
  "typedi": "^0.10.0",
115
+ "undici": "^7.9.0",
108
116
  "uuid": "^11.0.3",
109
117
  "winston": "^3.17.0",
110
- "winston-daily-rotate-file": "^5.0.0",
111
- "request-ip": "3.3.0",
112
- "ip2region": "2.3.0",
113
- "keyv": "^5.2.3",
114
- "@keyv/sqlite": "^4.0.1",
115
- "proper-lockfile": "^4.1.2",
116
- "compression": "^1.7.4",
117
- "helmet": "^8.1.0"
118
+ "winston-daily-rotate-file": "^5.0.0"
118
119
  },
119
120
  "devDependencies": {
120
- "moment": "2.30.1",
121
121
  "@ant-design/icons": "^5.0.1",
122
122
  "@ant-design/pro-layout": "6.38.22",
123
- "@codemirror/view": "^6.34.1",
124
- "@codemirror/state": "^6.4.1",
123
+ "@codemirror/state": "6.5.4",
124
+ "@codemirror/view": "6.39.16",
125
125
  "@monaco-editor/react": "4.2.1",
126
126
  "@react-hook/resize-observer": "^2.0.2",
127
- "react-router-dom": "6.26.1",
128
127
  "@types/body-parser": "^1.19.2",
128
+ "@types/compression": "^1.7.2",
129
129
  "@types/cors": "^2.8.12",
130
130
  "@types/cross-spawn": "^6.0.2",
131
131
  "@types/express": "^4.17.13",
132
132
  "@types/express-jwt": "^6.0.4",
133
133
  "@types/file-saver": "2.0.2",
134
+ "@types/helmet": "^4.0.0",
134
135
  "@types/js-yaml": "^4.0.5",
135
136
  "@types/jsonwebtoken": "^8.5.8",
136
137
  "@types/lodash": "^4.14.185",
@@ -138,17 +139,17 @@
138
139
  "@types/node": "^17.0.21",
139
140
  "@types/node-schedule": "^1.3.2",
140
141
  "@types/nodemailer": "^6.4.4",
142
+ "@types/proper-lockfile": "^4.1.4",
143
+ "@types/ps-tree": "^1.1.6",
141
144
  "@types/qrcode.react": "^1.0.2",
142
145
  "@types/react": "^18.0.20",
143
146
  "@types/react-copy-to-clipboard": "^5.0.4",
144
147
  "@types/react-dom": "^18.0.6",
148
+ "@types/request-ip": "0.0.41",
145
149
  "@types/serve-handler": "^6.1.1",
146
150
  "@types/sockjs": "^0.3.33",
147
151
  "@types/sockjs-client": "^1.5.1",
148
152
  "@types/uuid": "^8.3.4",
149
- "@types/request-ip": "0.0.41",
150
- "@types/proper-lockfile": "^4.1.4",
151
- "@types/ps-tree": "^1.1.6",
152
153
  "@uiw/codemirror-extensions-langs": "^4.21.9",
153
154
  "@uiw/react-codemirror": "^4.21.9",
154
155
  "@umijs/max": "^4.4.4",
@@ -160,9 +161,9 @@
160
161
  "axios": "^1.4.0",
161
162
  "compression-webpack-plugin": "9.2.0",
162
163
  "concurrently": "^7.0.0",
163
- "react-hotkeys-hook": "^4.6.1",
164
164
  "file-saver": "2.0.2",
165
165
  "lint-staged": "^13.0.3",
166
+ "moment": "2.30.1",
166
167
  "monaco-editor": "0.33.0",
167
168
  "nodemon": "^3.0.1",
168
169
  "prettier": "^2.5.1",
@@ -178,7 +179,9 @@
178
179
  "react-dnd": "^16.0.1",
179
180
  "react-dnd-html5-backend": "^16.0.1",
180
181
  "react-dom": "18.3.1",
182
+ "react-hotkeys-hook": "^4.6.1",
181
183
  "react-intl-universal": "^2.12.0",
184
+ "react-router-dom": "6.26.1",
182
185
  "react-split-pane": "^0.1.92",
183
186
  "sockjs-client": "^1.6.0",
184
187
  "ts-node": "^10.9.2",
@@ -186,8 +189,6 @@
186
189
  "tslib": "^2.4.0",
187
190
  "typescript": "5.2.2",
188
191
  "vh-check": "^2.0.5",
189
- "virtualizedtableforantd4": "1.3.0",
190
- "@types/compression": "^1.7.2",
191
- "@types/helmet": "^4.0.0"
192
+ "virtualizedtableforantd4": "1.3.0"
192
193
  }
193
194
  }
@@ -195,12 +195,14 @@ export SMTP_SERVER=""
195
195
  ## SMTP 发送邮件服务器是否使用 SSL,填写 true 或 false
196
196
  export SMTP_SSL=""
197
197
 
198
- ## smtp_email 填写 SMTP 收发件邮箱,通知将会由自己发给自己
198
+ ## smtp_email 填写 SMTP 发件邮箱
199
199
  export SMTP_EMAIL=""
200
200
  ## smtp_password 填写 SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
201
201
  export SMTP_PASSWORD=""
202
202
  ## smtp_name 填写 SMTP 收发件人姓名,可随意填写
203
203
  export SMTP_NAME=""
204
+ ## smtp_email_to 填写 SMTP 收件邮箱,多个用英文;分隔,不填默认发给发件邮箱
205
+ export SMTP_EMAIL_TO=""
204
206
 
205
207
  ## 17. PushMe
206
208
  ## 官方说明文档:https://push.i-i.me/
@@ -239,14 +241,19 @@ export NTFY_PASSWORD=""
239
241
  export NTFY_ACTIONS=""
240
242
 
241
243
  ## 21. wxPusher
242
- ## 官方文档: https://wxpusher.zjiecode.com/docs/
243
- ## 管理后台: https://wxpusher.zjiecode.com/admin/
244
+ ### 方式一:标准发送(更强大)
245
+ #### 官方文档: https://wxpusher.zjiecode.com/docs/
246
+ #### 管理后台: https://wxpusher.zjiecode.com/admin/
244
247
  ## wxPusher 的 appToken
245
248
  export WXPUSHER_APP_TOKEN=""
246
249
  ## wxPusher 的 topicIds,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
247
250
  export WXPUSHER_TOPIC_IDS=""
248
251
  ## wxPusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
249
252
  export WXPUSHER_UIDS=""
253
+ ### 方式二:极简发送(最简单,简单好用,一键配置,更推荐)
254
+ #### wxPusher 的 SPT(极简推送),扫码获取 https://wxpusher.zjiecode.com/docs/#/?id=spt
255
+ #### 多个用英文逗号,分隔,最多10个;与上面的 appToken 方式二选一即可
256
+ export WXPUSHER_SPT_LIST=""
250
257
 
251
258
  ## 22. 自定义通知
252
259
  ## 自定义通知 接收回调的URL
@@ -259,4 +266,13 @@ export WEBHOOK_METHOD=""
259
266
  ## 支持 text/plain、application/json、multipart/form-data、application/x-www-form-urlencoded
260
267
  export WEBHOOK_CONTENT_TYPE=""
261
268
 
269
+ ## 23. OpeniLink
270
+ ## 官方文档: https://openilink.com/docs/hub/apps
271
+ ## 在 OpeniLink Hub 后台安装 App 后获取 app_token
272
+ export OPENILINK_APP_TOKEN=""
273
+ ## OpeniLink Hub 地址,默认为 https://hub.openilink.com,自建 Hub 时填写自己的地址
274
+ export OPENILINK_HUB_URL=""
275
+ ## OpeniLink 的 context_token,用于标识消息会话上下文,可从消息事件中获取
276
+ export OPENILINK_CONTEXT_TOKEN=""
277
+
262
278
  ## 其他需要的变量,脚本中需要的变量使用 export 变量名= 声明即可
package/sample/notify.js CHANGED
@@ -108,8 +108,8 @@ const push_config = {
108
108
 
109
109
  QYWX_KEY: '', // 企业微信机器人的 webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa
110
110
 
111
- TG_BOT_TOKEN: '', // tg 机器人的 TG_BOT_TOKEN,例:1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ
112
- TG_USER_ID: '', // tg 机器人的 TG_USER_ID,例:1434078534
111
+ TG_BOT_TOKEN: '', // tg 机器人的 TG_BOT_TOKEN,例:1234567890:ABCdefGHIjklMNOpqrsTUVwxyz
112
+ TG_USER_ID: '', // tg 机器人的 TG_USER_ID,例:1234567890
113
113
  TG_API_HOST: 'https://api.telegram.org', // tg 代理 api
114
114
  TG_PROXY_AUTH: '', // tg 代理认证参数
115
115
  TG_PROXY_HOST: '', // tg 机器人的 TG_PROXY_HOST
@@ -121,7 +121,8 @@ const push_config = {
121
121
 
122
122
  SMTP_SERVICE: '', // 邮箱服务名称,比如 126、163、Gmail、QQ 等,支持列表 https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json
123
123
  SMTP_EMAIL: '', // SMTP 发件邮箱
124
- SMTP_TO: '', // SMTP 收件邮箱,默认通知将会发给发件邮箱
124
+ SMTP_TO: '', // SMTP 收件邮箱,兼容旧参数名,默认通知将会发给发件邮箱
125
+ SMTP_EMAIL_TO: '', // SMTP 收件邮箱,多个分号分隔,默认发给发件邮箱
125
126
  SMTP_PASSWORD: '', // SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
126
127
  SMTP_NAME: '', // SMTP 收发件人姓名,可随意填写
127
128
 
@@ -146,11 +147,21 @@ const push_config = {
146
147
  NTFY_PASSWORD: '', // 推送用户密码,可选
147
148
  NTFY_ACTIONS: '', // 推送用户动作,可选
148
149
 
150
+ // 方式一:标准发送(更强大)
149
151
  // 官方文档: https://wxpusher.zjiecode.com/docs/
150
152
  // 管理后台: https://wxpusher.zjiecode.com/admin/
151
153
  WXPUSHER_APP_TOKEN: '', // wxpusher 的 appToken
152
154
  WXPUSHER_TOPIC_IDS: '', // wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
153
155
  WXPUSHER_UIDS: '', // wxpusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
156
+ // 方式二:极简发送(最简单,简单好用,一键配置,更推荐)
157
+ // wxPusher 的 SPT(极简推送),扫码获取 https://wxpusher.zjiecode.com/docs/#/?id=spt
158
+ // 多个用英文逗号,分隔,最多10个;与上面的 appToken 方式二选一即可
159
+ WXPUSHER_SPT_LIST: '', // wxpusher 的 SPT(极简推送),多个用英文逗号,分隔,最多10个
160
+
161
+ // 官方文档: https://openilink.com/docs/hub/apps
162
+ OPENILINK_APP_TOKEN: '', // OpeniLink 的 app_token,在 OpeniLink Hub 后台安装 App 后获取
163
+ OPENILINK_HUB_URL: '', // OpeniLink Hub 地址,默认为 https://hub.openilink.com,自建 Hub 时填写自己的地址
164
+ OPENILINK_CONTEXT_TOKEN: '', // OpeniLink 的 context_token,用于标识消息会话上下文,可从消息事件中获取
154
165
  };
155
166
 
156
167
  for (const key in push_config) {
@@ -301,7 +312,7 @@ function serverNotify(text, desp) {
301
312
  console.log('Server 酱发送通知调用API失败😞\n', err);
302
313
  } else {
303
314
  // server酱和Server酱·Turbo版的返回json格式不太一样
304
- if (data.errno === 0 || data.data.errno === 0) {
315
+ if (data.errno === 0 || data.code === 0) {
305
316
  console.log('Server 酱发送通知消息成功🎉\n');
306
317
  } else if (data.errno === 1024) {
307
318
  // 一分钟内发送相同的内容会触发
@@ -1046,8 +1057,14 @@ function fsBotNotify(text, desp) {
1046
1057
  }
1047
1058
 
1048
1059
  async function smtpNotify(text, desp) {
1049
- const { SMTP_EMAIL, SMTP_TO, SMTP_PASSWORD, SMTP_SERVICE, SMTP_NAME } =
1050
- push_config;
1060
+ const {
1061
+ SMTP_EMAIL,
1062
+ SMTP_TO,
1063
+ SMTP_EMAIL_TO,
1064
+ SMTP_PASSWORD,
1065
+ SMTP_SERVICE,
1066
+ SMTP_NAME,
1067
+ } = push_config;
1051
1068
  if (![SMTP_EMAIL, SMTP_PASSWORD].every(Boolean) || !SMTP_SERVICE) {
1052
1069
  return;
1053
1070
  }
@@ -1063,9 +1080,20 @@ async function smtpNotify(text, desp) {
1063
1080
  });
1064
1081
 
1065
1082
  const addr = SMTP_NAME ? `"${SMTP_NAME}" <${SMTP_EMAIL}>` : SMTP_EMAIL;
1083
+ const recipients = [SMTP_EMAIL_TO, SMTP_TO].reduce((list, value) => {
1084
+ if (!value) {
1085
+ return list;
1086
+ }
1087
+ return list.concat(
1088
+ value
1089
+ .split(/[;;]/)
1090
+ .map((item) => item.trim())
1091
+ .filter(Boolean),
1092
+ );
1093
+ }, []);
1066
1094
  const info = await transporter.sendMail({
1067
1095
  from: addr,
1068
- to: SMTP_TO ? SMTP_TO.split(';') : addr,
1096
+ to: recipients.length ? recipients : SMTP_EMAIL,
1069
1097
  subject: text,
1070
1098
  html: `${desp.replace(/\n/g, '<br/>')}`,
1071
1099
  });
@@ -1408,6 +1436,112 @@ function wxPusherNotify(text, desp) {
1408
1436
  });
1409
1437
  }
1410
1438
 
1439
+ function wxPusherSptNotify(text, desp) {
1440
+ return new Promise((resolve) => {
1441
+ const { WXPUSHER_SPT_LIST } = push_config;
1442
+ if (WXPUSHER_SPT_LIST) {
1443
+ // 处理 SPT,将逗号分隔的字符串转为数组
1444
+ const spts = WXPUSHER_SPT_LIST.split(',')
1445
+ .map((spt) => spt.trim())
1446
+ .filter((spt) => spt);
1447
+
1448
+ if (!spts.length) {
1449
+ console.log('wxpusher SPT 不能为空!!');
1450
+ return resolve();
1451
+ }
1452
+ if (spts.length > 10) {
1453
+ console.log('wxpusher SPT 最多支持 10 个!!');
1454
+ return resolve();
1455
+ }
1456
+
1457
+ const body = {
1458
+ content: `<h1>${text}</h1><br/><div style='white-space: pre-wrap;'>${desp}</div>`,
1459
+ summary: text,
1460
+ contentType: 2,
1461
+ // 单个 SPT 用 spt,多个用 sptList
1462
+ ...(spts.length === 1 ? { spt: spts[0] } : { sptList: spts }),
1463
+ };
1464
+
1465
+ const options = {
1466
+ url: 'https://wxpusher.zjiecode.com/api/send/message/simple-push',
1467
+ body: JSON.stringify(body),
1468
+ headers: {
1469
+ 'Content-Type': 'application/json',
1470
+ },
1471
+ timeout,
1472
+ };
1473
+
1474
+ $.post(options, (err, resp, data) => {
1475
+ try {
1476
+ if (err) {
1477
+ console.log('wxpusher SPT 发送通知消息失败!\n', err);
1478
+ } else {
1479
+ if (data.code === 1000) {
1480
+ console.log('wxpusher SPT 发送通知消息完成!');
1481
+ } else {
1482
+ console.log(`wxpusher SPT 发送通知消息异常:${data.msg}`);
1483
+ }
1484
+ }
1485
+ } catch (e) {
1486
+ $.logErr(e, resp);
1487
+ } finally {
1488
+ resolve(data);
1489
+ }
1490
+ });
1491
+ } else {
1492
+ resolve();
1493
+ }
1494
+ });
1495
+ }
1496
+
1497
+ function openiLinkNotify(text, desp) {
1498
+ return new Promise((resolve) => {
1499
+ const { OPENILINK_APP_TOKEN, OPENILINK_HUB_URL, OPENILINK_CONTEXT_TOKEN } =
1500
+ push_config;
1501
+ if (OPENILINK_APP_TOKEN) {
1502
+ const baseUrl = OPENILINK_HUB_URL
1503
+ ? OPENILINK_HUB_URL.replace(/\/$/, '')
1504
+ : 'https://hub.openilink.com';
1505
+ const body = {
1506
+ type: 'text',
1507
+ content: `${text}\n\n${desp}`,
1508
+ };
1509
+ if (OPENILINK_CONTEXT_TOKEN) {
1510
+ body.context_token = OPENILINK_CONTEXT_TOKEN;
1511
+ }
1512
+ const options = {
1513
+ url: `${baseUrl}/bot/v1/message/send`,
1514
+ body: JSON.stringify(body),
1515
+ headers: {
1516
+ 'Content-Type': 'application/json',
1517
+ Authorization: `Bearer ${OPENILINK_APP_TOKEN}`,
1518
+ },
1519
+ timeout,
1520
+ };
1521
+
1522
+ $.post(options, (err, resp, data) => {
1523
+ try {
1524
+ if (err) {
1525
+ console.log('OpeniLink 发送通知消息失败!\n', err);
1526
+ } else {
1527
+ if (data.ok) {
1528
+ console.log('OpeniLink 发送通知消息成功!');
1529
+ } else {
1530
+ console.log(`OpeniLink 发送通知消息异常:${data.error}`);
1531
+ }
1532
+ }
1533
+ } catch (e) {
1534
+ $.logErr(e, resp);
1535
+ } finally {
1536
+ resolve(data);
1537
+ }
1538
+ });
1539
+ } else {
1540
+ resolve();
1541
+ }
1542
+ });
1543
+ }
1544
+
1411
1545
  function parseString(input, valueFormatFn) {
1412
1546
  const regex = /(\w+):\s*((?:(?!\n\w+:).)*)/g;
1413
1547
  const matches = {};
@@ -1511,7 +1645,7 @@ async function sendNotify(text, desp, params = {}) {
1511
1645
  }
1512
1646
  }
1513
1647
 
1514
- if (push_config.HITOKOTO !== 'false') {
1648
+ if (![false, 'false'].includes(push_config.HITOKOTO)) {
1515
1649
  desp += '\n\n' + (await one());
1516
1650
  }
1517
1651
 
@@ -1527,7 +1661,7 @@ async function sendNotify(text, desp, params = {}) {
1527
1661
  iGotNotify(text, desp, params), // iGot
1528
1662
  gobotNotify(text, desp), // go-cqhttp
1529
1663
  gotifyNotify(text, desp), // gotify
1530
- chatNotify(text, desp), // synolog chat
1664
+ chatNotify(text, desp), // synology chat
1531
1665
  pushDeerNotify(text, desp), // PushDeer
1532
1666
  aibotkNotify(text, desp), // 智能微秘书
1533
1667
  fsBotNotify(text, desp), // 飞书机器人
@@ -1538,6 +1672,8 @@ async function sendNotify(text, desp, params = {}) {
1538
1672
  qmsgNotify(text, desp), // 自定义通知
1539
1673
  ntfyNotify(text, desp), // Ntfy
1540
1674
  wxPusherNotify(text, desp), // wxpusher
1675
+ wxPusherSptNotify(text, desp), // wxpusher SPT
1676
+ openiLinkNotify(text, desp), // OpeniLink
1541
1677
  ]);
1542
1678
  }
1543
1679
 
package/sample/notify.py CHANGED
@@ -94,8 +94,8 @@ push_config = {
94
94
 
95
95
  'QYWX_KEY': '', # 企业微信机器人
96
96
 
97
- 'TG_BOT_TOKEN': '', # tg 机器人的 TG_BOT_TOKEN,例:1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ
98
- 'TG_USER_ID': '', # tg 机器人的 TG_USER_ID,例:1434078534
97
+ 'TG_BOT_TOKEN': '', # tg 机器人的 TG_BOT_TOKEN,例:1234567890:ABCdefGHIjklMNOpqrsTUVwxyz
98
+ 'TG_USER_ID': '', # tg 机器人的 TG_USER_ID,例:1234567890
99
99
  'TG_API_HOST': '', # tg 代理 api
100
100
  'TG_PROXY_AUTH': '', # tg 代理认证参数
101
101
  'TG_PROXY_HOST': '', # tg 机器人的 TG_PROXY_HOST
@@ -107,7 +107,8 @@ push_config = {
107
107
 
108
108
  'SMTP_SERVER': '', # SMTP 发送邮件服务器,形如 smtp.exmail.qq.com:465
109
109
  'SMTP_SSL': 'false', # SMTP 发送邮件服务器是否使用 SSL,填写 true 或 false
110
- 'SMTP_EMAIL': '', # SMTP 收发件邮箱,通知将会由自己发给自己
110
+ 'SMTP_EMAIL': '', # SMTP 发件邮箱
111
+ 'SMTP_EMAIL_TO': '', # SMTP 收件邮箱,多个分号分隔,默认发给发件邮箱
111
112
  'SMTP_PASSWORD': '', # SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
112
113
  'SMTP_NAME': '', # SMTP 收发件人姓名,可随意填写
113
114
 
@@ -132,9 +133,20 @@ push_config = {
132
133
  'NTFY_PASSWORD': '', # 推送用户密码,可选
133
134
  'NTFY_ACTIONS': '', # 推送用户动作,可选
134
135
 
136
+ ### 方式一:标准发送(更强大)
137
+ #### 官方文档: https://wxpusher.zjiecode.com/docs/
138
+ #### 管理后台: https://wxpusher.zjiecode.com/admin/
135
139
  'WXPUSHER_APP_TOKEN': '', # wxpusher 的 appToken 官方文档: https://wxpusher.zjiecode.com/docs/ 管理后台: https://wxpusher.zjiecode.com/admin/
136
140
  'WXPUSHER_TOPIC_IDS': '', # wxpusher 的 主题ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
137
141
  'WXPUSHER_UIDS': '', # wxpusher 的 用户ID,多个用英文分号;分隔 topic_ids 与 uids 至少配置一个才行
142
+ ### 方式二:极简发送(最简单,简单好用,一键配置,更推荐)
143
+ #### wxPusher 的 SPT(极简推送),扫码获取 https://wxpusher.zjiecode.com/docs/#/?id=spt
144
+ #### 多个用英文逗号,分隔,最多10个;与上面的 appToken 方式二选一即可
145
+ 'WXPUSHER_SPT_LIST': '', # wxpusher 的 SPT(极简推送),多个用英文逗号,分隔,最多10个 官方文档: https://wxpusher.zjiecode.com/docs/#/?id=spt
146
+
147
+ 'OPENILINK_APP_TOKEN': '', # OpeniLink 的 app_token,在 OpeniLink Hub 后台安装 App 后获取 官方文档: https://openilink.com/docs/hub/apps
148
+ 'OPENILINK_HUB_URL': '', # OpeniLink Hub 地址,默认为 https://hub.openilink.com,自建 Hub 时填写自己的地址
149
+ 'OPENILINK_CONTEXT_TOKEN': '', # OpeniLink 的 context_token,用于标识消息会话上下文,可从消息事件中获取
138
150
  }
139
151
  # fmt: on
140
152
 
@@ -690,6 +702,10 @@ def smtp(title: str, content: str) -> None:
690
702
  return
691
703
  print("SMTP 邮件 服务启动")
692
704
 
705
+ email_to = push_config.get("SMTP_EMAIL_TO") or push_config.get("SMTP_EMAIL")
706
+ email_to_list = [
707
+ item.strip() for item in re.split(r"[;;]", email_to) if item.strip()
708
+ ]
693
709
  message = MIMEText(content, "plain", "utf-8")
694
710
  message["From"] = formataddr(
695
711
  (
@@ -697,12 +713,7 @@ def smtp(title: str, content: str) -> None:
697
713
  push_config.get("SMTP_EMAIL"),
698
714
  )
699
715
  )
700
- message["To"] = formataddr(
701
- (
702
- Header(push_config.get("SMTP_NAME"), "utf-8").encode(),
703
- push_config.get("SMTP_EMAIL"),
704
- )
705
- )
716
+ message["To"] = ",".join(email_to_list)
706
717
  message["Subject"] = Header(title, "utf-8")
707
718
 
708
719
  try:
@@ -716,7 +727,7 @@ def smtp(title: str, content: str) -> None:
716
727
  )
717
728
  smtp_server.sendmail(
718
729
  push_config.get("SMTP_EMAIL"),
719
- push_config.get("SMTP_EMAIL"),
730
+ email_to_list,
720
731
  message.as_bytes(),
721
732
  )
722
733
  smtp_server.close()
@@ -898,6 +909,90 @@ def wxpusher_bot(title: str, content: str) -> None:
898
909
  print(f"wxpusher 推送失败!错误信息:{response.get('msg')}")
899
910
 
900
911
 
912
+ def wxpusher_spt(title: str, content: str) -> None:
913
+ """
914
+ 通过 wxpusher 极简推送(SPT)推送消息。
915
+ 支持的环境变量:
916
+ - WXPUSHER_SPT_LIST: SPT, 多个用英文逗号,分隔, 最多10个
917
+ """
918
+ if not push_config.get("WXPUSHER_SPT_LIST"):
919
+ return
920
+
921
+ # 处理 SPT,将逗号分隔的字符串转为数组
922
+ spts = [
923
+ spt.strip()
924
+ for spt in push_config.get("WXPUSHER_SPT_LIST").split(",")
925
+ if spt.strip()
926
+ ]
927
+
928
+ if not spts:
929
+ print("wxpusher 服务的 WXPUSHER_SPT_LIST 不能为空!!")
930
+ return
931
+ if len(spts) > 10:
932
+ print("wxpusher 服务的 WXPUSHER_SPT_LIST 最多支持 10 个!!")
933
+ return
934
+
935
+ print("wxpusher SPT 服务启动")
936
+
937
+ url = "https://wxpusher.zjiecode.com/api/send/message/simple-push"
938
+
939
+ data = {
940
+ "content": f"<h1>{title}</h1><br/><div style='white-space: pre-wrap;'>{content}</div>",
941
+ "summary": title,
942
+ "contentType": 2,
943
+ }
944
+ # 单个 SPT 用 spt,多个用 sptList
945
+ if len(spts) == 1:
946
+ data["spt"] = spts[0]
947
+ else:
948
+ data["sptList"] = spts
949
+
950
+ headers = {"Content-Type": "application/json"}
951
+ response = requests.post(url=url, json=data, headers=headers).json()
952
+
953
+ if response.get("code") == 1000:
954
+ print("wxpusher SPT 推送成功!")
955
+ else:
956
+ print(f"wxpusher SPT 推送失败!错误信息:{response.get('msg')}")
957
+
958
+
959
+ def openilink(title: str, content: str) -> None:
960
+ """
961
+ 通过 OpeniLink 推送消息。
962
+ 支持的环境变量:
963
+ - OPENILINK_APP_TOKEN: 在 OpeniLink Hub 后台安装 App 后获取的 app_token
964
+ - OPENILINK_HUB_URL: OpeniLink Hub 地址,默认为 https://hub.openilink.com
965
+ - OPENILINK_CONTEXT_TOKEN: 消息会话上下文 token,可从消息事件中获取
966
+ """
967
+ if not push_config.get("OPENILINK_APP_TOKEN"):
968
+ return
969
+
970
+ print("OpeniLink 服务启动")
971
+
972
+ base_url = (
973
+ push_config.get("OPENILINK_HUB_URL", "").rstrip("/")
974
+ or "https://hub.openilink.com"
975
+ )
976
+ url = f"{base_url}/bot/v1/message/send"
977
+ headers = {
978
+ "Content-Type": "application/json",
979
+ "Authorization": f'Bearer {push_config.get("OPENILINK_APP_TOKEN")}',
980
+ }
981
+ data = {
982
+ "type": "text",
983
+ "content": f"{title}\n\n{content}",
984
+ }
985
+ if push_config.get("OPENILINK_CONTEXT_TOKEN"):
986
+ data["context_token"] = push_config.get("OPENILINK_CONTEXT_TOKEN")
987
+
988
+ response = requests.post(url=url, json=data, headers=headers).json()
989
+
990
+ if response.get("ok"):
991
+ print("OpeniLink 推送成功!")
992
+ else:
993
+ print(f'OpeniLink 推送失败!错误信息:{response.get("error")}')
994
+
995
+
901
996
  def parse_headers(headers):
902
997
  if not headers:
903
998
  return {}
@@ -1063,6 +1158,10 @@ def add_notify_function():
1063
1158
  push_config.get("WXPUSHER_TOPIC_IDS") or push_config.get("WXPUSHER_UIDS")
1064
1159
  ):
1065
1160
  notify_function.append(wxpusher_bot)
1161
+ if push_config.get("WXPUSHER_SPT_LIST"):
1162
+ notify_function.append(wxpusher_spt)
1163
+ if push_config.get("OPENILINK_APP_TOKEN"):
1164
+ notify_function.append(openilink)
1066
1165
  if not notify_function:
1067
1166
  print(f"无推送渠道,请检查通知变量是否正确")
1068
1167
  return notify_function
@@ -1088,7 +1187,7 @@ def send(title: str, content: str, ignore_default_config: bool = False, **kwargs
1088
1187
  return
1089
1188
 
1090
1189
  hitokoto = push_config.get("HITOKOTO")
1091
- content += "\n\n" + one() if hitokoto != "false" else ""
1190
+ content += "\n\n" + one() if hitokoto not in [False, "false"] else ""
1092
1191
 
1093
1192
  notify_function = add_notify_function()
1094
1193
  ts = [