├── .gitignore
├── README.md
├── deleteDuplicateTasksImplement.py
└── deleteDuplicateTasksNotify.py
/.gitignore:
--------------------------------------------------------------------------------
1 | deleteDuplicateTasks.py
2 | token.txt
3 | .idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 清理青龙面板重复任务
2 |
3 |
4 |
5 | **警告:本程序仅通过任务名称判断是否重复,不排除误删的可能**
6 |
7 | ## 使用本仓库前提
8 |
9 | 安装了青龙面板,且能通过`/ql/config/auth.json`路径访问到用户名,密码,和token
10 |
11 |
12 |
13 | ## 使用方法:
14 |
15 | 1、将仓库的clone下来,将其放在/ql/scripts下,目录结构如下
16 |
17 |
18 |
19 | 2、青龙面板中如下添加任务
20 |
21 |
22 |
23 | 3、可以直接运行一下试试
24 |
25 | 原先一共有:
26 |
27 |
28 |
29 | 点击运行:
30 |
31 |
32 |
33 | 查看日志:
34 |
35 |
36 |
37 | 回去再看一下:
38 |
39 |
40 |
41 |
42 |
43 | ## 代码运行流程:
44 |
45 | 1、读取/ql/config/auth.json中的token,向localhost:5700发起请求,获得task列表
46 |
47 | 2、对比task的名称,仅保留不重复的任务
48 |
49 | 3、向对应api发出delete请求,删除重复的任务
50 |
51 |
52 |
53 | # 鸣谢:
54 |
55 | 本仓库的推送功能来自curtinlv@github:https://github.com/curtinlv/JD-Script/blob/main/sendNotify.py,在他的代码的基础上,我修改了server酱推送的一个bug(其他推送方式我没测试)
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/deleteDuplicateTasksImplement.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import json
3 | import os,sys
4 | import requests
5 | import time
6 |
7 | ip="localhost"
8 |
9 | def loadSend():
10 | print("加载推送功能")
11 | global send
12 | cur_path = os.path.abspath(os.path.dirname(__file__))
13 | sys.path.append(cur_path)
14 | if os.path.exists(cur_path + "/deleteDuplicateTasksNotify.py"):
15 | try:
16 | from deleteDuplicateTasksNotify import send
17 | except:
18 | print("加载通知服务失败~")
19 |
20 | headers={
21 | "Accept": "application/json",
22 | "Authorization": "Basic YWRtaW46YWRtaW4=",
23 | "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36",
24 | }
25 |
26 | def getTaskList():
27 | t = round(time.time() * 1000)
28 | url = "http://%s:5700/api/crons?searchValue=&t=%d" % (ip, t)
29 | response = requests.get(url=url, headers=headers)
30 | responseContent=json.loads(response.content.decode('utf-8'))
31 | if responseContent['code']==200:
32 | taskList= responseContent['data']
33 | return taskList
34 | else:
35 | # 没有获取到taskList,返回空
36 | return []
37 |
38 |
39 | def getDuplicate(taskList):
40 | wholeNames={}
41 | duplicateID=[]
42 | for task in taskList:
43 | if task['name'] in wholeNames.keys():
44 | duplicateID.append(task['_id'])
45 | else:
46 | wholeNames[task['name']] = 1
47 | return duplicateID
48 |
49 |
50 | def getData(duplicateID):
51 | rawData = "["
52 | count=0
53 | for id in duplicateID:
54 | rawData += "\"%s\""%id
55 | if count 1:
57 | PUSH_PLUS_TOKEN = os.environ["PUSH_PLUS_TOKEN"]
58 | # print("已获取并使用Env环境 PUSH_PLUS_TOKEN")
59 | # 获取企业微信应用推送 QYWX_AM
60 | if "QYWX_AM" in os.environ:
61 | if len(os.environ["QYWX_AM"]) > 1:
62 | QYWX_AM = os.environ["QYWX_AM"]
63 | # print("已获取并使用Env环境 QYWX_AM")
64 |
65 | if BARK:
66 | notify_mode.append('bark')
67 | # print("BARK 推送打开")
68 | if SCKEY:
69 | notify_mode.append('sc_key')
70 | # print("Server酱 推送打开")
71 | if TG_BOT_TOKEN and TG_USER_ID:
72 | notify_mode.append('telegram_bot')
73 | # print("Telegram 推送打开")
74 | if DD_BOT_ACCESS_TOKEN and DD_BOT_SECRET:
75 | notify_mode.append('dingding_bot')
76 | # print("钉钉机器人 推送打开")
77 | if QQ_SKEY and QQ_MODE:
78 | notify_mode.append('coolpush_bot')
79 | # print("QQ机器人 推送打开")
80 |
81 | if PUSH_PLUS_TOKEN:
82 | notify_mode.append('pushplus_bot')
83 | # print("微信推送Plus机器人 推送打开")
84 | if QYWX_AM:
85 | notify_mode.append('wecom_app')
86 | # print("企业微信机器人 推送打开")
87 |
88 |
89 | def message(str_msg):
90 | global message_info
91 | print(str_msg)
92 | message_info = "{}\n{}".format(message_info, str_msg)
93 | sys.stdout.flush()
94 |
95 | def bark(title, content):
96 | print("\n")
97 | if not BARK:
98 | print("bark服务的bark_token未设置!!\n取消推送")
99 | return
100 | print("bark服务启动")
101 | try:
102 | response = requests.get(
103 | f"""https://api.day.app/{BARK}/{title}/{urllib.parse.quote_plus(content)}""").json()
104 | if response['code'] == 200:
105 | print('推送成功!')
106 | else:
107 | print('推送失败!')
108 | except:
109 | print('推送失败!')
110 |
111 | def serverJ(title, content):
112 | if not SCKEY:
113 | print("server酱服务的SCKEY未设置!!\n取消推送")
114 | return
115 | # print("serverJ服务启动")
116 | data = {
117 | "text": title,
118 | "desp": content.replace("\n", "\n\n")
119 | }
120 | response = requests.post(f"https://sc.ftqq.com/{SCKEY}.send", data=data).json()
121 | if response['code'] == 0:
122 | print('推送成功!')
123 | else:
124 | print('推送失败!')
125 |
126 | # tg通知
127 | def telegram_bot(title, content):
128 | try:
129 | print("\n")
130 | bot_token = TG_BOT_TOKEN
131 | user_id = TG_USER_ID
132 | if not bot_token or not user_id:
133 | print("tg服务的bot_token或者user_id未设置!!\n取消推送")
134 | return
135 | print("tg服务启动")
136 | if TG_API_HOST:
137 | if 'http' in TG_API_HOST:
138 | url = f"{TG_API_HOST}/bot{TG_BOT_TOKEN}/sendMessage"
139 | else:
140 | url = f"https://{TG_API_HOST}/bot{TG_BOT_TOKEN}/sendMessage"
141 | else:
142 | url = f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage"
143 |
144 | headers = {'Content-Type': 'application/x-www-form-urlencoded'}
145 | payload = {'chat_id': str(TG_USER_ID), 'text': f'{title}\n\n{content}', 'disable_web_page_preview': 'true'}
146 | proxies = None
147 | if TG_PROXY_IP and TG_PROXY_PORT:
148 | proxyStr = "http://{}:{}".format(TG_PROXY_IP, TG_PROXY_PORT)
149 | proxies = {"http": proxyStr, "https": proxyStr}
150 | try:
151 | response = requests.post(url=url, headers=headers, params=payload, proxies=proxies).json()
152 | except:
153 | print('推送失败!')
154 | if response['ok']:
155 | print('推送成功!')
156 | else:
157 | print('推送失败!')
158 | except Exception as e:
159 | print(e)
160 |
161 | def dingding_bot(title, content):
162 | timestamp = str(round(time.time() * 1000)) # 时间戳
163 | secret_enc = DD_BOT_SECRET.encode('utf-8')
164 | string_to_sign = '{}\n{}'.format(timestamp, DD_BOT_SECRET)
165 | string_to_sign_enc = string_to_sign.encode('utf-8')
166 | hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
167 | sign = urllib.parse.quote_plus(base64.b64encode(hmac_code)) # 签名
168 | print('开始使用 钉钉机器人 推送消息...', end='')
169 | url = f'https://oapi.dingtalk.com/robot/send?access_token={DD_BOT_ACCESS_TOKEN}×tamp={timestamp}&sign={sign}'
170 | headers = {'Content-Type': 'application/json;charset=utf-8'}
171 | data = {
172 | 'msgtype': 'text',
173 | 'text': {'content': f'{title}\n\n{content}'}
174 | }
175 | response = requests.post(url=url, data=json.dumps(data), headers=headers, timeout=15).json()
176 | if not response['errcode']:
177 | print('推送成功!')
178 | else:
179 | print('推送失败!')
180 |
181 | def coolpush_bot(title, content):
182 | print("\n")
183 | if not QQ_SKEY or not QQ_MODE:
184 | print("qq服务的QQ_SKEY或者QQ_MODE未设置!!\n取消推送")
185 | return
186 | print("qq服务启动")
187 | url=f"https://qmsg.zendee.cn/{QQ_MODE}/{QQ_SKEY}"
188 | payload = {'msg': f"{title}\n\n{content}".encode('utf-8')}
189 | response = requests.post(url=url, params=payload).json()
190 | if response['code'] == 0:
191 | print('推送成功!')
192 | else:
193 | print('推送失败!')
194 | # push推送
195 | def pushplus_bot(title, content):
196 | try:
197 | print("\n")
198 | if not PUSH_PLUS_TOKEN:
199 | print("PUSHPLUS服务的token未设置!!\n取消推送")
200 | return
201 | print("PUSHPLUS服务启动")
202 | url = 'http://www.pushplus.plus/send'
203 | data = {
204 | "token": PUSH_PLUS_TOKEN,
205 | "title": title,
206 | "content": content
207 | }
208 | body = json.dumps(data).encode(encoding='utf-8')
209 | headers = {'Content-Type': 'application/json'}
210 | response = requests.post(url=url, data=body, headers=headers).json()
211 | if response['code'] == 200:
212 | print('推送成功!')
213 | else:
214 | print('推送失败!')
215 | except Exception as e:
216 | print(e)
217 | # 企业微信 APP 推送
218 | def wecom_app(title, content):
219 | try:
220 | if not QYWX_AM:
221 | print("QYWX_AM 并未设置!!\n取消推送")
222 | return
223 | QYWX_AM_AY = re.split(',', QYWX_AM)
224 | if 4 < len(QYWX_AM_AY) > 5:
225 | print("QYWX_AM 设置错误!!\n取消推送")
226 | return
227 | corpid = QYWX_AM_AY[0]
228 | corpsecret = QYWX_AM_AY[1]
229 | touser = QYWX_AM_AY[2]
230 | agentid = QYWX_AM_AY[3]
231 | try:
232 | media_id = QYWX_AM_AY[4]
233 | except:
234 | media_id = ''
235 | wx = WeCom(corpid, corpsecret, agentid)
236 | # 如果没有配置 media_id 默认就以 text 方式发送
237 | if not media_id:
238 | message = title + '\n\n' + content
239 | response = wx.send_text(message, touser)
240 | else:
241 | response = wx.send_mpnews(title, content, media_id, touser)
242 | if response == 'ok':
243 | print('推送成功!')
244 | else:
245 | print('推送失败!错误信息如下:\n', response)
246 | except Exception as e:
247 | print(e)
248 |
249 | class WeCom:
250 | def __init__(self, corpid, corpsecret, agentid):
251 | self.CORPID = corpid
252 | self.CORPSECRET = corpsecret
253 | self.AGENTID = agentid
254 |
255 | def get_access_token(self):
256 | url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
257 | values = {'corpid': self.CORPID,
258 | 'corpsecret': self.CORPSECRET,
259 | }
260 | req = requests.post(url, params=values)
261 | data = json.loads(req.text)
262 | return data["access_token"]
263 |
264 | def send_text(self, message, touser="@all"):
265 | send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + self.get_access_token()
266 | send_values = {
267 | "touser": touser,
268 | "msgtype": "text",
269 | "agentid": self.AGENTID,
270 | "text": {
271 | "content": message
272 | },
273 | "safe": "0"
274 | }
275 | send_msges = (bytes(json.dumps(send_values), 'utf-8'))
276 | respone = requests.post(send_url, send_msges)
277 | respone = respone.json()
278 | return respone["errmsg"]
279 |
280 | def send_mpnews(self, title, message, media_id, touser="@all"):
281 | send_url = 'https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=' + self.get_access_token()
282 | send_values = {
283 | "touser": touser,
284 | "msgtype": "mpnews",
285 | "agentid": self.AGENTID,
286 | "mpnews": {
287 | "articles": [
288 | {
289 | "title": title,
290 | "thumb_media_id": media_id,
291 | "author": "Author",
292 | "content_source_url": "",
293 | "content": message.replace('\n', '
'),
294 | "digest": message
295 | }
296 | ]
297 | }
298 | }
299 | send_msges = (bytes(json.dumps(send_values), 'utf-8'))
300 | respone = requests.post(send_url, send_msges)
301 | respone = respone.json()
302 | return respone["errmsg"]
303 |
304 | def send(title, content):
305 | """
306 | 使用 bark, telegram bot, dingding bot, serverJ 发送手机推送
307 | :param title:
308 | :param content:
309 | :return:
310 | """
311 | for i in notify_mode:
312 | if i == 'bark':
313 | if BARK:
314 | bark(title=title, content=content)
315 | else:
316 | print('未启用 bark')
317 | continue
318 | if i == 'sc_key':
319 | if SCKEY:
320 | serverJ(title=title, content=content)
321 | else:
322 | print('未启用 Server酱')
323 | continue
324 | elif i == 'dingding_bot':
325 | if DD_BOT_ACCESS_TOKEN and DD_BOT_SECRET:
326 | dingding_bot(title=title, content=content)
327 | else:
328 | print('未启用 钉钉机器人')
329 | continue
330 | elif i == 'telegram_bot':
331 | if TG_BOT_TOKEN and TG_USER_ID:
332 | telegram_bot(title=title, content=content)
333 | else:
334 | print('未启用 telegram机器人')
335 | continue
336 | elif i == 'coolpush_bot':
337 | if QQ_SKEY and QQ_MODE:
338 | coolpush_bot(title=title, content=content)
339 | else:
340 | print('未启用 QQ机器人')
341 | continue
342 | elif i == 'pushplus_bot':
343 | if PUSH_PLUS_TOKEN:
344 | pushplus_bot(title=title, content=content)
345 | else:
346 | print('未启用 PUSHPLUS机器人')
347 | continue
348 | elif i == 'wecom_app':
349 | if QYWX_AM:
350 | wecom_app(title=title, content=content)
351 | else:
352 | print('未启用企业微信应用消息推送')
353 | continue
354 | else:
355 | print('此类推送方式不存在')
356 |
357 |
358 | def main():
359 | send('title', 'content')
360 |
361 |
362 | if __name__ == '__main__':
363 | main()
--------------------------------------------------------------------------------