├── .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 | image-20210820220115801 18 | 19 | 2、青龙面板中如下添加任务 20 | 21 | image-20210820224311591 22 | 23 | 3、可以直接运行一下试试 24 | 25 | 原先一共有: 26 | 27 | image-20210820221200972 28 | 29 | 点击运行: 30 | 31 | image-20210820221125603 32 | 33 | 查看日志: 34 | 35 | image-20210820221341094 36 | 37 | 回去再看一下: 38 | 39 | image-20210820221407319 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() --------------------------------------------------------------------------------