├── .gitignore
├── OnePlus.py
├── README.md
├── SunLogin.py
├── fun
├── __init__.py
├── baidu.py
├── code.py
└── com.py
├── image
├── 1.png
└── 3.png
├── notify.py
└── wpspc.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/OnePlus.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | File: OnePlus.py(OnePlus签到)
6 | Author: ytt447735
7 | cron: 0 8 * * *
8 | new Env('OnePlus签到');
9 | Update: 2024/10/19
10 | """
11 | import os,notify
12 | import ujson
13 | import requests
14 | import re
15 | import time
16 | from fun import com
17 |
18 | class oneplus:
19 | def __init__(self):
20 | self.ck = ''
21 | self.Log = ""
22 | self.UA = "Mozilla/5.0 (Linux; Android 14; LE2120 Build/UKQ1.230924.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36 oppostore/403201 ColorOS/V14.0.0 brand/OnePlus model/LE2120;kyc/h5face;kyc/2.0;netType:NETWORK_WIFI;appVersion:403201;packageName:com.oppo.store"
23 | self.activityId_activityInfo = ""
24 | self.activityId_taskActivityInfo = ""
25 |
26 | # 获取签到标识
27 | def get_activityId(self):
28 | url = "https://hd.opposhop.cn/bp/b371ce270f7509f0?nightModelEnable=true&us=wode&um=qiandaobanner"
29 | payload = {}
30 | headers = {
31 | 'Cookie': self.ck,
32 | 'User-Agent': self.UA
33 | }
34 | response = requests.request("GET", url, headers=headers, data=payload)
35 | # print(response.text)
36 | # "activityInfo":{"activityId":"1838147945355288576",
37 | # "taskActivityInfo":{"activityId":"1838149802563739648",
38 | match = re.search(r'"activityInfo":{"activityId":"(\d+)"', response.text)
39 | if match:
40 | # return self.shopping_signIn(match.group(1))
41 | self.activityId_activityInfo = match.group(1)
42 | print(f"activactivityId_activityInfoityId={self.activityId_activityInfo}")
43 | else:
44 | print("签到标识获取失败")
45 | self.Log = self.Log + f"📝签到失败,签到标识获取失败!\n"
46 |
47 | match = re.search(r'"taskActivityInfo":{"activityId":"(\d+)"', response.text)
48 | if match:
49 | self.activityId_taskActivityInfo = match.group(1)
50 | print(f"activityId_taskActivityInfo={self.activityId_taskActivityInfo}")
51 | else:
52 | print("任务标识获取失败")
53 | self.Log = self.Log + f"📝签到失败,任务标识获取失败!\n"
54 |
55 |
56 |
57 | # 商城签到
58 | def shopping_signIn(self):
59 | if self.activityId_activityInfo =="":
60 | return
61 | url = "https://hd.opposhop.cn/api/cn/oapi/marketing/cumulativeSignIn/signIn"
62 | payload = ujson.dumps({
63 | "activityId": self.activityId_activityInfo
64 | })
65 | headers = {
66 | 'Cookie': self.ck,
67 | 'User-Agent': self.UA,
68 | 'Content-Type': 'application/json'
69 | }
70 | response = requests.request("POST", url, headers=headers, data=payload)
71 | print("shopping_signIn",response.text)
72 | j = ujson.loads(response.text)
73 | if j["code"] == 200:
74 | awardType = j['data']['awardType']
75 | awardValue = j['data']['awardType']
76 | if awardType == 1:
77 | self.Log = self.Log + f"📝签到成功,奖励{ awardValue } 积分\n"
78 | else:
79 | message = j['message']
80 | self.Log = self.Log + f"📝签到失败,{ message }\n"
81 |
82 |
83 | # 积分额度查询
84 | def integral_query(self):
85 | url = "https://msec.opposhop.cn/users/web/memberCenter/assets?couponStatus=1&couponType=0"
86 | payload = {}
87 | headers = {
88 | 'Cookie': self.ck,
89 | 'User-Agent': self.UA
90 | }
91 | response = requests.request("GET", url, headers=headers, data=payload)
92 | print("integral_query",response.text)
93 | j = ujson.loads(response.text)
94 | if j["code"] == 200:
95 | self.Log = self.Log + "💰当前余额:\n"
96 | for i, element in enumerate(j["data"]):
97 | title = element["title"]
98 | text = element["text"]
99 | Type = element["type"]
100 | if Type == "coupon" or Type == "credit" or Type == "growing":
101 | self.Log = self.Log + f"👛{ title }:{ text }\n"
102 |
103 |
104 | # 会员等级
105 | def membership_grade(self):
106 | url = "https://msec.opposhop.cn/users/web/memberCenter/getMemberExpDetail"
107 | payload = {}
108 | headers = {
109 | 'Cookie': self.ck,
110 | 'User-Agent': self.UA
111 | }
112 | response = requests.request("GET", url, headers=headers, data=payload)
113 | print("membership_grade",response.text)
114 | j = ujson.loads(response.text)
115 | if j["code"] == 200:
116 | gradeName = j['data']['gradeName']
117 | des = j['data']['des']
118 | self.Log = self.Log + f"🎖️会员等级:{ gradeName }({ des })\n"
119 |
120 |
121 | # 获取任务列表
122 | def get_task(self):
123 | if self.activityId_taskActivityInfo=="":
124 | return
125 | url = f"https://hd.opposhop.cn/api/cn/oapi/marketing/task/queryTaskList?activityId={ self.activityId_taskActivityInfo }&source=c"
126 | payload = {}
127 | headers = {
128 | 'Cookie': self.ck,
129 | 'Accept': 'application/json, text/plain, */*',
130 | 'User-Agent': self.UA
131 | }
132 | response = requests.request("GET", url, headers=headers, data=payload)
133 | print("get_task",response.text)
134 | j = ujson.loads(response.text)
135 | if j["code"] == 200:
136 | for i, element in enumerate(j["data"]["taskDTOList"]):
137 | taskName = element['taskName']
138 | taskId = element['taskId']
139 | activityId = element['activityId']
140 | taskType = element['taskType'] # 1=浏览,4=预约, 6=开卡/购买
141 | taskStatus = element['taskStatus'] # 是否完成
142 | attachConfigTwo_link = element['attachConfigTwo']['link']
143 | skuId = ''
144 | match = re.search(r'skuId=(\d+)', attachConfigTwo_link)
145 | if match:
146 | skuId = match.group(1)
147 |
148 |
149 | tt = self.button_text_status(element)
150 | if tt == 2:
151 | self.task_signInOrShareTask(taskName, taskId, activityId)
152 | elif tt==3:
153 | print(f"skuId={skuId}")
154 | self.subscribes(skuId,taskName, taskId, activityId)
155 | else:
156 | self.Log = self.Log + f"❌{ taskName } 任务执行失败,{ tt }\n"
157 | time.sleep(3)
158 |
159 | # 提交任务
160 | def task_signInOrShareTask(self, taskName, taskId, activityId):
161 | url = f"https://hd.opposhop.cn/api/cn/oapi/marketing/taskReport/signInOrShareTask?taskId={ taskId }&activityId={ activityId }&taskType=1"
162 | payload = {}
163 | headers = {
164 | 'Cookie': self.ck,
165 | 'Accept': 'application/json, text/plain, */*',
166 | 'User-Agent': self.UA
167 | }
168 | response = requests.request("GET", url, headers=headers, data=payload)
169 | print("task_signInOrShareTask",response.text)
170 | j = ujson.loads(response.text)
171 | if j["code"] == 200:
172 | self.task_receiveAward(taskName, taskId, activityId)
173 | else:
174 | message = j['message']
175 | self.Log = self.Log + f"❌{ taskName } 任务提交失败,{ message }\n"
176 |
177 |
178 |
179 | # 领取任务奖励
180 | def task_receiveAward(self, taskName, taskId, activityId):
181 | url = f"https://hd.opposhop.cn/api/cn/oapi/marketing/task/receiveAward?taskId={ taskId }&activityId={ activityId }"
182 | payload = {}
183 | headers = {
184 | 'Cookie': self.ck,
185 | 'Accept': 'application/json, text/plain, */*',
186 | 'User-Agent': self.UA
187 | }
188 | response = requests.request("GET", url, headers=headers, data=payload)
189 | print("task_receiveAward",response.text)
190 | j = ujson.loads(response.text)
191 | if j["code"] == 200:
192 | awardType = j['data']['awardType']
193 | awardValue = j['data']['awardType']
194 | if awardType == 1:
195 | self.Log = self.Log + f"✅{taskName} 任务完成,奖励{ awardValue } 积分\n"
196 | else:
197 | message = j['message']
198 | self.Log = self.Log + f"❌{ taskName } 任务失败,{ message }\n"
199 |
200 | # 预约任务
201 | def subscribes(self, skuId,taskName, taskId, activityId):
202 | url = "https://msec.opposhop.cn/goods/web/subscribes/goodsSubscribeV1"
203 | payload = f"type=1&skuId={ skuId }"
204 | headers = {
205 | 'Cookie': self.ck,
206 | 'Content-Type': 'application/x-www-form-urlencoded',
207 | 'User-Agent': 'okhttp/4.9.3.6'
208 | }
209 | response = requests.post(url, data=payload, headers=headers)
210 | # response = requests.request("POST", url, headers=headers, data=payload)
211 | print("subscribes",response.text)
212 | j = ujson.loads(response.text)
213 | if j["code"] == 200:
214 | self.task_receiveAward(taskName, taskId, activityId)
215 | else:
216 | message = j['errorMessage']
217 | self.Log = self.Log + f"❌{ taskName } 预约失败,{ message }\n"
218 |
219 | # 新增日志
220 | def set_log(self,text):
221 | self.Log = self.Log + text
222 |
223 |
224 | # 获取日志
225 | def get_log(self):
226 | # return self.Log.replace("\n","\r\n")
227 | return self.Log
228 |
229 |
230 |
231 | def button_text_status(self,t):
232 | TASK_STATUS = {
233 | 'PREPARE_FINISH': 1,
234 | 'GO_AWARD': 2,
235 | 'FINISHED': 3,
236 | 'NOT_REMAINING_NUMBER': 6
237 | }
238 | task_type_texts = [
239 | 1,# "立即签到",
240 | 2,# "去看看",
241 | 4,# "去分享",
242 | 2,# "去逛逛",
243 | 3,# "去预约",
244 | 3,# "去预约",
245 | 3,# "去预约",
246 | 5,# "去购买",
247 | 6,# "去组队",
248 | 2,# "去看看",
249 | 3,# "去预约",
250 | 7,# "去完成",
251 | 8,# "去添加",
252 | 9,# "去认证",
253 | 10,# "去关注",
254 | 11,# "去填写",
255 | 2,# "去逛逛",
256 | 2,# "去看看"
257 | ]
258 |
259 | if t['taskStatus'] == TASK_STATUS['PREPARE_FINISH']:
260 | # return task_type_texts.get(t['taskType'], "已结束")
261 | return task_type_texts[t['taskType']]
262 | elif t['taskStatus'] == TASK_STATUS['GO_AWARD']:
263 | return "领奖励"
264 | elif t['taskStatus'] == TASK_STATUS['NOT_REMAINING_NUMBER']:
265 | return "领光了"
266 | elif t['taskStatus'] == TASK_STATUS['FINISHED']:
267 | return "已完成"
268 | else:
269 | return "已结束"
270 |
271 |
272 | # 钱包签到
273 | def continueSign(self):
274 | url = "https://hwallet.finzfin.com/act/usersign/v1/continueSign"
275 |
276 | payload = ujson.dumps({
277 | "actId": "AID202207111442220933",
278 | "funcId": "CONTINUEV2202209161649037309"
279 | })
280 |
281 | headers = {
282 | 'User-Agent': "Mozilla/5.0 (Linux; Android 14; LE2120 Build/UKQ1.230924.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/128.0.6613.146 Mobile Safari/537.36;webank/h5face;webank/2.0 JSBridge/1 wallet/5.31.0_befb176_240927 FinshellWebSDK/3.0.2.74",
283 | 'Accept': "application/json;charset=UTF-8",
284 | 'Content-Type': "application/json",
285 | 'x-token': "TOKEN_eyJhbGciOiJFQ0RTQSIsInYiOiIxIn0.eyJleHAiOjE3MzE4Mzc3NzYyMTgsImlkIjoiNjk5ODkzMDU5IiwiaWRjIjoic2hvdW1pbmciLCJ0aWQiOiJYR2VCNUN4SkRyM25MN0lna2R5aHZ0RlFIczNWdXF1d3hNdTNBWFM4UGZPMHdwcXh0WmtXTkVWWGJ0cTJNTEZOS1dYK2Rpa0xmakZnZ2luNEtxK0JpZm0rTEdVeUtJNWdvUDlqbG9RVlpmST0ifQ.MEUCIQDTYNCBx3iliVXlR79AUkyZdPRfoCzePXtw2mY2eDIyuAIgF6hirnqnJunzzQpr1yq86QLQEWwaPGXOIlPV_GU6UBo"
286 | }
287 |
288 | response = requests.post(url, data=payload, headers=headers)
289 | # response = requests.request("POST", url, headers=headers, data=payload)
290 | print("continueSign", response.text)
291 | j = ujson.loads(response.text)
292 | if j["code"] == 200:
293 | print(1)
294 | else:
295 | message = j['msg']
296 | self.Log = self.Log + f"❌签到失败,{ message }\n"
297 |
298 |
299 | # 一加论坛签到
300 | def bbsSign(self):
301 | url = "https://bbs-api-cn.oneplus.com/task/api/sign/v1/create"
302 | params = {
303 | 'ver': "bbs42703",
304 | 'timestamp': com.get_time(),
305 | # 'sign': ""
306 | }
307 | headers = {
308 | 'User-Agent': "bbs/android/42703",
309 | 'Accept-Encoding': "gzip",
310 | 'model': "LE2120",
311 | 'osver': "android14",
312 | 'romv': "LE2120_14.0.0.720(CN01)",
313 | 'lang': "zh-CN",
314 | 'token': com.GetIntermediateText(self.ck,"TOKENSID=",";"),
315 | 'tz': "Asia/Shanghai"
316 | }
317 | response = requests.post(url, params=params, headers=headers)
318 | print(response.text)
319 | j = ujson.loads(response.text)
320 | if j["code"] == 200:
321 | # if j['data']['todaySigned']==True:
322 | # self.Log = self.Log +'今天已经签到过啦!\n'
323 | # else:
324 | # self.Log = self.Log +'今天签到成功!\n'
325 | # self.Log = self.Log + '累计签到:'+str(j['data']['signDays'])+'天\n'
326 | # self.Log = self.Log + '连续签到:'+str(j['data']['continuousSignDays'])+'天\n'
327 | # self.Log = self.Log + '再连续签到'+str(j['data']['extSignDays'])+'天,可额外获得'+str(j['data']['extCredit'])+'积分\n'
328 | self.Log = self.Log +'今天签到成功!\n'
329 | else:
330 | self.Log = self.Log +"一加论坛签到失败,"+j['msg']+"\n"
331 |
332 |
333 | def run(self):
334 | OnePlus_COOKIE = os.getenv("OnePlus_COOKIE")
335 | if not OnePlus_COOKIE:
336 | notify.send("OnePlus_COOKIE",'🙃OnePlus_COOKIE 变量未设置')
337 | print('🙃OnePlus_COOKIE 变量未设置')
338 | exit()
339 | ck_list = OnePlus_COOKIE.split('&')
340 | print("-------------------总共" + str(int(len(ck_list))) + "🙃OnePlus_COOKIE CK-------------------")
341 | for mt_token in ck_list:
342 | # try:
343 | self.ck = mt_token
344 | self.set_log("\n--------一加论坛签到--------\n")
345 | r.bbsSign()
346 | self.set_log("\n--------OPPO商城任务--------\n")
347 | t = self.get_activityId()
348 | self.shopping_signIn()
349 | self.get_task()
350 | self.membership_grade()
351 | self.integral_query()
352 | # self.continueSign()
353 | print(self.get_log())
354 | notify.send("OnePlus", self.get_log())
355 | # except Exception as e:
356 | # print("出错了!详细错误👇错误CK👉" + mt_token)
357 | # print(e)
358 | # notify.send("OnePlus", "出错了!详细错误👇错误CK👉" + mt_token +"\n错误内容:" + str(e))
359 |
360 |
361 | if __name__ == '__main__':
362 | r = oneplus()
363 | r.run()
364 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #### 功能
2 | | 名称 | 功能 | 变量获取 | 变量名 | 变量模版 |
3 | |:-------|:------------------------------------------------------------------------|:------------------------------|:------------------------------|:------------------------------|
4 | | wps pc | pc端签到领取兑换vip时间
云空间签到领取容量
| [获取](https://vip.wps.cn/home) | wps_pc | wpsua=***;wps_sid=***;day=1 |
5 | | OPPO积分 | OPPO商城签到、每日任务、一加论坛签到 | Reqable抓包获取CK | OnePlus_COOKIE | TOKENSID=***;apkPkg=*** |
6 | | 贝锐 | 阳光小店每日签到、每日任务 | [获取](https://www.oray.com/) | BR_COOKIE | _s_id_=*** |
7 |
8 | ---
9 | #### 使用
10 | 青龙面板
11 |
12 | ##### 拉库
13 | ```
14 | ql repo https://github.com/ytt447735/automation.git fun|notify.py fun main py
15 | ```
16 | ##### 环境变量
17 | PC(day等于每日签到时自动兑换天数,可不设):
18 | ```
19 | wps_pc
20 | wpsua=***;wps_sid=***;day=1
21 | ```
22 | ##### 依赖
23 | ```
24 | ujson
25 | requests
26 | ```
27 | #### 验证码识别配置
28 | 之前版本采用的是百度的手写文字识别功能,[获取](https://console.bce.baidu.com/ai/?_=1722298138766#/ai/ocr/overview/index)
29 | 在"/fun/baidu.py"文件内修改"API_KEY"、"SECRET_KEY"的值
30 | 百度识别准确率低,已替换,原代码保留着,可自行替换
31 | 新代码已采用YOLOv8模型识别,准确率98%左右,识别模型代码暂不开放,识别接口暂免费提供
32 |
33 | #### CK失效
34 | 目前测试发现CK好像不会过期,一直有效
35 |
36 |
37 |
38 | WPS签到打码部署
39 |
40 | 犹豫各位需求有点多,我服务器压力有点大,各位自行部署吧
41 | 部署完毕后 http://IP:8080/ 打开能看见“Hello, World!”说明部署成功了
42 | 最后替换对应的fun/code.py中的链接
43 | ```
44 | docker run -d \
45 | --name wps_verification \
46 | -p 8080:8080 \
47 | --restart unless-stopped \
48 | ytt4477/wps_verification:latest \
49 | /bin/bash -c /apps/run.sh
50 | ```
51 |
52 |
53 |
54 | ---
55 | #### 预览
56 | WPS
57 |
58 | 
59 |
60 |
--------------------------------------------------------------------------------
/SunLogin.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | File: SunLogin.py(贝锐签到)
6 | Author: ytt447735
7 | cron: 2 8 * * *
8 | new Env('贝锐签到');
9 | Update: 2024/10/19
10 | """
11 | import ujson
12 | import requests
13 | import base64
14 | import hashlib
15 | import time
16 | import os
17 | import notify
18 |
19 | class sunlogin:
20 | def __init__(self):
21 | self.ck = ''
22 | self.Log = ""
23 |
24 |
25 | # 阳光小店-每日签到
26 | def income(self):
27 | url = "https://store-api.oray.com/point/1/income"
28 | headers = {
29 | 'User-Agent': "SLCC/15.3.1.66811 (Android)",
30 | 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8",
31 | 'Referer': "https://sunlight.oray.com/",
32 | 'Cookie': self.ck
33 | }
34 | response = requests.post(url, headers=headers)
35 | print(response.text)
36 | if "code" in response.text:
37 | j = ujson.loads(response.text)
38 | self.Log = self.Log + j['message'] +'\n'
39 | return
40 | if "userid" in response.text:
41 | j = ujson.loads(response.text)
42 | self.Log = self.Log + "签到成功,获得🌞" + str(j['pointtotal']) + '阳光值\n'
43 | return
44 | self.Log = self.Log + "签到失败,未知错误\n"
45 |
46 |
47 | def sign(self):
48 | url = "https://store-api.oray.com/points/sign"
49 | headers = {
50 | 'User-Agent': "SLCC/15.3.1.66811 (Android)",
51 | 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8",
52 | 'Referer': "https://sunlight.oray.com/",
53 | 'Cookie': self.ck
54 | }
55 | response = requests.get(url, headers=headers)
56 | print(response.text)
57 | if '签到成功' in response.text:
58 | j = ujson.loads(response.text)
59 | self.Log = self.Log + j['arguments']['dialogtitle'] + j['arguments']['dialogdesc']+"\n"
60 | else:
61 | self.Log = self.Log + "签到失败"+"\n"
62 |
63 |
64 | #收集阳光
65 | def production(self, pointdailyid):
66 | url = f"https://store-api.oray.com/points/{pointdailyid}/daily"
67 | headers = {
68 | 'User-Agent': "SLCC/15.3.1.66811 (Android)",
69 | 'Accept': "application/json, text/plain, */*",
70 | 'Accept-Encoding': "gzip, deflate, br, zstd",
71 | 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8",
72 | 'Referer': "https://sunlight.oray.com/",
73 | 'Accept-Language': "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
74 | 'Cookie': self.ck
75 | }
76 | response = requests.post(url, headers=headers)
77 | print(response.text)
78 | if "code" in response.text:
79 | j = ujson.loads(response.text)
80 | self.Log = self.Log +j["message"]+"\n"
81 | else:
82 | self.Log = self.Log + "☀️x1 收集成功\n"
83 |
84 |
85 | # 获取阳光列表
86 | def getDailys(self):
87 | url = f"https://store-api.oray.com/points/daily"
88 | headers = {
89 | # 'User-Agent': "SLCC/15.3.1.66811 (Android)",
90 | # 'Accept': "application/json, text/plain, */*",
91 | # 'Accept-Encoding': "gzip, deflate, br, zstd",
92 | 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8",
93 | 'Referer': "https://sunlight.oray.com/",
94 | # 'Accept-Language': "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
95 | 'Cookie': self.ck
96 | }
97 | response = requests.get(url, headers=headers)
98 | print("getDailys:"+response.text + '🔚')
99 | j = ujson.loads(response.text)
100 | for i, element in enumerate(j):
101 | id = element['pointdailyid']
102 | userid = element['userid']
103 | print(id)
104 | self.production(id)
105 | time.sleep(2)
106 |
107 | # 获取阳光余额
108 | def getPlants(self):
109 | url = "https://store-api.oray.com/point/plants"
110 | headers = {
111 | # 'User-Agent': "SLCC/15.3.1.66811 (Android)",
112 | # 'Accept': "application/json, text/plain, */*",
113 | # 'Accept-Encoding': "gzip, deflate, br, zstd",
114 | 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8",
115 | 'Referer': "https://sunlight.oray.com/",
116 | # 'Accept-Language': "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
117 | 'Cookie': self.ck
118 | }
119 | response = requests.get(url, headers=headers)
120 | print("getPlants:"+response.text)
121 | if '' == response.text:
122 | return False
123 | j = ujson.loads(response.text)
124 | if "pointtotal" in response.text:
125 | self.Log = self.Log +"☀️余额:"+str(j['pointtotal'])+"\n"
126 | return True
127 | else:
128 | self.Log = self.Log +"☀️余额:未知\n"
129 | return False
130 |
131 | # 提交任务
132 | def setIncome(self,key):
133 | url = "https://store-api.oray.com/point/0/income"
134 | k = key.replace('=','%3D')
135 | payload = f"point_key={k}"
136 | headers = {
137 | # 'User-Agent': "SLCC/15.3.1.66811 (Android)",
138 | # 'Accept': "application/json, text/plain, */*",
139 | # 'Accept-Encoding': "gzip, deflate, br, zstd",
140 | 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8",
141 | 'Referer': "https://sunlight.oray.com/",
142 | # 'Accept-Language': "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
143 | 'Cookie': self.ck
144 | }
145 | response = requests.post(url, data=payload, headers=headers)
146 | print("setIncome:"+response.text)
147 | message = ''
148 | if 'userid' in response.text:
149 | return True, message
150 | if 'message' in response.text:
151 | j = ujson.loads(response.text)
152 | message = j['message']
153 | return False, message
154 |
155 |
156 | # 获取任务列表
157 | def getPoints(self,brand):
158 | url = f'https://store-api.oray.com/points?brand={brand}'
159 | headers = {
160 | # 'User-Agent': "SLCC/15.3.1.66811 (Android)",
161 | # 'Accept': "application/json, text/plain, */*",
162 | # 'Accept-Encoding': "gzip, deflate, br, zstd",
163 | 'Content-Type': "application/x-www-form-urlencoded;charset=utf-8",
164 | 'Referer': "https://sunlight.oray.com/",
165 | # 'Accept-Language': "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
166 | 'Cookie': self.ck
167 | }
168 | response = requests.get(url, headers=headers)
169 | print("getDailys:"+response.text)
170 | j = ujson.loads(response.text)
171 | for i, element in enumerate(j):
172 | name = element['name']
173 | count = element['condition']['count']
174 | used = element['used']
175 | print(count,used)
176 | if used == count:
177 | self.Log = self.Log + name +f"({str(count)}/{str(count)}) ✅已完成\n"
178 | continue
179 | acc = used
180 | for i in range(count-used):
181 | pointid = element['pointid']
182 | print(pointid,count,used)
183 | pointid = self.pointjm(str(pointid))
184 | message = ''
185 | isOK, message = self.setIncome(pointid)
186 | if isOK:
187 | acc = acc + 1
188 | message = '✅已完成'
189 | else:
190 | message = "❌失败,"+message
191 | time.sleep(10)
192 | # break
193 | self.Log = self.Log + name +f"({str(acc)}/{str(count)}) {message}\n"
194 | time.sleep(3)
195 | # break
196 |
197 |
198 | # 加密
199 | def pointjm(self, t):
200 | from Crypto.Cipher import AES
201 | from Crypto.Util.Padding import pad
202 | key = "Nx4xnfHmGzz4t1rH"
203 | l = hashlib.md5(key.encode()).hexdigest()
204 | c = l[:16]
205 | d = l.encode('utf-8')
206 | h = c.encode('utf-8')
207 | cipher = AES.new(d, AES.MODE_CBC, h)
208 | e = t.encode('utf-8')
209 | n = cipher.encrypt(pad(e, AES.block_size))
210 | return base64.b64encode(n).decode('utf-8')
211 | # Example usage
212 | # t = "3"
213 | # result = encrypt(t)
214 | # print(result) # Output should be "flEnHDBJMbe1mlNaEFKtzw=="
215 |
216 | # flEnHDBJMbe1mlNaEFKtzw==
217 |
218 |
219 | # 新增日志
220 | def set_log(self,text):
221 | self.Log = self.Log + text
222 |
223 |
224 | # 获取日志
225 | def get_log(self):
226 | # return self.Log.replace("\n","\r\n")
227 | return self.Log
228 |
229 | # 执行
230 | def run(self):
231 | task_name = '贝锐'
232 | ck_value = 'BR_COOKIE'
233 | CKS = os.getenv(ck_value)
234 | if not CKS:
235 | notify.send(task_name,f'🙃{ck_value} 变量未设置')
236 | print(f'🙃{ck_value} 变量未设置')
237 | exit()
238 | CKS_list = CKS.split('&')
239 | print("-------------------总共" + str(int(len(CKS_list))) + f"个{ck_value} CK-------------------")
240 | for mt_token in CKS_list:
241 | # try:
242 | self.ck = mt_token
243 | if self.getPlants() == False:
244 | self.set_log('⚠️ '+mt_token+ ' CK失效了')
245 | continue
246 | self.set_log("\n--------阳光小店签到--------\n")
247 | self.income()
248 | self.getDailys() # 收集阳光
249 | self.set_log("\n--------阳光任务--------\n")
250 | self.getPoints(3)
251 | self.getPoints(2)
252 | self.getPoints(0)
253 | self.getPlants() #最终额度
254 | # except Exception as e:
255 | # print("出错了!详细错误👇错误CK👉" + mt_token)
256 | # print(e)
257 | # notify.send(task_name, "出错了!详细错误👇错误CK👉" + mt_token +"\n错误内容:" + str(e))
258 | print(self.get_log())
259 | notify.send(task_name, self.get_log())
260 |
261 |
262 | if __name__ == '__main__':
263 | w = sunlogin()
264 | w.run()
--------------------------------------------------------------------------------
/fun/__init__.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 |
4 | # 获取当前文件的目录
5 | current_dir = os.path.dirname(os.path.abspath(__file__))
6 |
7 | # 将 fun 文件夹添加到 sys.path
8 | sys.path.append(current_dir)
9 |
--------------------------------------------------------------------------------
/fun/baidu.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import urllib
3 | import requests
4 | import ujson
5 |
6 | # 百度手写识别key
7 | API_KEY = ""
8 | SECRET_KEY = ""
9 |
10 |
11 | def get_manage(base64):
12 | url = "https://aip.baidubce.com/rest/2.0/ocr/v1/handwriting?access_token=" + get_access_token()
13 |
14 | # image 可以通过 get_file_content_as_base64("C:\fakepath\segment_1.png",True) 方法获取
15 | payload = {
16 | "image": base64,
17 | "detect_direction": "false",
18 | "probability": "false",
19 | "detect_alteration": "false"
20 | }
21 | # payload = 'image=iVBORw0KGgoAAAANSUhEUgAAAEgAAABYCAIAAADZWSaLAAAIt0lEQVR4nO1bf0iTzx%2B%2FfcdYIiIjZISYyLAVIhEjRCxkmVhIiZnIEBkyRCRKJMWGxBgyRCKGyIgYYiEmERLDxggRMREbMkS0Yo0xZMiQKRJD1hC5zx%2F3%2Fd7n7T3PfjzPZrkve%2F2159537%2Ff7dfc8d%2Fd%2B302CMUb%2Fj%2FjP33bgtJAjlm3IEcs25IhlG3LEsg05YtmGHLFsQ47YH8fW1lZ%2Ff%2F%2Fly5dv3bolpj0%2BY3A6ncXFxYyTDQ0NQvVkgJjH40lfCcGjR48yNQDpEqOuHB0dpaNneno68Zul0%2BkEKUyLWDQapYYHBwfFKXG73RqNJukn4%2Ff7BalNi1goFKKGFQrF%2Fv6%2BUA1v377lcpBKpU6nE59MxgjVnBaxQCAAba%2BtrXErtLe3I4Tq6%2BsPDg6gyO%2F35%2BXlcVnV19d7vV6MscfjoYWFhYXRaPSvEdvc3ITS8fFxKDWbzVTkcrm4lFQqVSgUonWqq6up6N69e0J9S%2Fcbg73u8%2FlI%2Bfz8PNfvvr4%2BIp2bm%2BNKLRbL8fEx1by0tASli4uLf5QYxlipVFLzLpdrc3MT9jTEysoKxvj169dMuVwu%2F%2FbtG6O2tLQU1hHhWLrESkpKqPmamhqpVMqlpNfryRcSjUaLioqgaHBwMBaLMTqZGWVqauovEGtoaEAIyWQy3rVVq9W6XC5YH46w1WpVq9UIoa6urhM%2BAVy9elWcY2kROz4%2B7uzsbG1t9fv9Xq%2BXYbW0tMRt4na7idRsNsPZxWQyMRUIRHxdBOKJDQ8PI4Sampr%2B1fU%2F9Pb2pqJhdHQUctjY2MAYP3%2F%2BHBaKdk9My%2B3t7Zs3bxLDAwMDpJDMhBqNZnZ2NkU9a2trkMPTp0%2Fxyfewo6NDhHsEgolNTU1B27W1tRsbGz09PXl5eaOjo0K1wfHJz8%2FHnKMfnU4XDAaFqsWCiAWDwWvXrqH4WFhYEGr%2B8PAQanA6nZnSnCoxn8%2FHrC0Iod7eXolEQh%2B5rY6Pj%2Bfm5paXlxNolslkVENTUxOzX6H49etX5oltb28zZiQSicPhwCffnPX1daahTqcjosLCQrfbzavcarVCJRjjcDjc2NjIWKysrMwwMa1Wy9hobW39tz0AoUoQiUTOnz%2FPNAwEAlz9kUiEIUYQDAabmpqgaH5%2BPjPEgsHg9evXGefogoMx9vl8UEQ3wSsrK4gPWq2W3wmE6A7mxYsXjIhCIpGkHpUlIlZeXs54ZjQaYYX19XVuZ%2Fv9fl5WBHD%2FTnB0dGQwGBYWFoi2srIyGIy%2FfPkSNq%2BqqkqX2MePHxmfZmZmuD5xiV24cCEBsbGxMa6toaGhlpYWjLHD4WhubmaGpa2tDWrY2dlJixgM%2B%2BN9uGazmdbRaDTBYFChUEAnJBKJ1%2BttaWlJ3OXLy8u0X0Kh0MjICOslgFqtjkQi4olhjA8PD9vb200mUzxFVVVVkFh9fT30oLq6mlRjwjNeVdXV1T9%2B%2FKA0VldXodRut0MNVqs1LWJJwf0IISsYzEMRDCgpZmdntVotmffKysqKi4uZ7S9M%2BCiVylMkBt9VLsLh8AkzALzx1cbGBpGura1ZLBbyG37V5HVNPOyZIQbdvXLlCrT6%2BfNnWofsGOrq6qiUN60bjUYrKytJBchhenqaaw4hlHQDKZ7Y5uYmNZOfn09%2Fz83N4ZOTqsPhmJiYSNrfcCqCMBqNZAEgUSnB0NDQaREzmUwIodLS0p2dndraWmJveHgYY8zQqKioYN5bXoXv37%2FnJYYQUqvVHo%2Fn8ePHtEShUJwWMYPBgBBaXV2lO3Sr1RoIBPR6PeMWiTthCe9unQnPYDaFt%2BS0iEHtCCGtVkvGkEFVVRWZHsvKymhhZ2cnV%2BH%2B%2Fj5M9djtdmZ%2FzOBUiO3u7hLtMzMzRqMxnu3JyUmMcSQSmZiYgGu3TCbjVUveAoJXr17hOKlVhFB3d%2FepEGtubiYGysvL4%2B2hPnz4QCqTTFYq%2FW2z2WiFuro6Uri4uMhtzmSdM0MsFosVFhYylmDutq%2Bvj25W4uVPadoYghmf7e1tUj47OwvLmQggY8TgRA9HoKCgAIGVx%2B1206WJCzJ%2FMmDiIJjAC4fDNpstXrSaGWK9vb1cR0k6pKenh9RhZnyEkEqlgut4vEwoHGFxOWDxxKC7TExht9sxX8iDEPJ6vcxKxat8cHCQVtDr9X%2BOGJ0PCcbHx2mOESGk0%2Bm6u7u5rOhuPSkxuJEvKCgQcZgokhjzjkWj0cnJSS4TBjTPAwt5c%2BDMARJJD4uA4Hse7969o7%2B7urrOnTuXyj2MGzdufP%2F%2BnSn88uULt%2BalS5fg4%2B%2Ffv4V6%2BF8I7QnYllyEgCfREDabDe5FlEplOBwmJ7cEjY2NvCZUKhWt84cOJeBUIZfLScgYDochn7t378IQE06hFRUVDoeDPpaUlPBagUlFOs2eIjFmkaFnykw6ta2tjWkol8upFG5TiouLeY%2FMyTkOgVQqPXViTCbshBYAlUrFNGSSWRA0zwHB7KFEsMKCiEFjFoslngghxD1THhkZ4SUWL7mbPrFUZ8WvX7%2FCxzt37sBHGPkjhLa2tpjmz5496%2Bzs5Krd29vjNQcPQN68eZOikyeQYgfAnQ43SQSnBIQQNzHIHYfENWEvaDSa1AeKIqUR%2B%2FTp0%2BrqKn188uQJU%2BH%2B%2FftDQ0P08eLFi7x6uDn9nz9%2F8ta8ffs2%2FQ2v6AhAYt6xWIx7LhGvMgndZTJZgiz0wMAAVFVTU8NbjVkbUxwliCRtxsbGGFZkmxsPXq93d3c3sU44kdBglMczgKRhJU%2FzxOKOjg6GGA3%2B0gHpL%2BZ6BwOa%2BUIIGQwGoSaSEGMOTpNmGjIIuEyLeBuTNDg4OKAH6lKpNJVjjkyBycYJbZ68Abl%2Bk5eXl3pYnilAYkKv5p65W9wQ8M4gycaljrN77x4h9ODBA%2FobxoGp4EwT6%2B%2Fvp%2FdIHj58KKitBJ%2FtP3jv7e0VFRWJcPKsExONM%2F0qpoMcsWxDjli2IUcs25Ajlm3IEcs25IhlG%2F4BarRllGnmfvIAAAAASUVORK5CYII%3D&detect_direction=false&probability=false&detect_alteration=false'
22 | headers = {
23 | 'Content-Type': 'application/x-www-form-urlencoded',
24 | 'Accept': 'application/json'
25 | }
26 | response = requests.request("POST", url, headers=headers, data=payload)
27 | print(response.text)
28 | j = ujson.loads(response.text)
29 | return j['words_result_num']
30 |
31 |
32 | def get_file_content_as_base64(path, urlencoded=False):
33 | """
34 | 获取文件base64编码
35 | :param path: 文件路径
36 | :param urlencoded: 是否对结果进行urlencoded
37 | :return: base64编码信息
38 | """
39 | with open(path, "rb") as f:
40 | content = base64.b64encode(f.read()).decode("utf8")
41 | if urlencoded:
42 | content = urllib.parse.quote_plus(content)
43 | return content
44 |
45 |
46 | def get_access_token():
47 | """
48 | 使用 AK,SK 生成鉴权签名(Access Token)
49 | :return: access_token,或是None(如果错误)
50 | """
51 | url = "https://aip.baidubce.com/oauth/2.0/token"
52 | params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
53 | return str(requests.post(url, params=params).json().get("access_token"))
54 |
--------------------------------------------------------------------------------
/fun/code.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | import re
4 | import base64
5 |
6 | # 识别验证码
7 | def identify(mo,code,model):
8 | url = f"http://cn-hk-bgp-4.ofalias.net:50818/inference_wps_{mo}"
9 | payload = code
10 | headers = {
11 | 'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
12 | 'Content-Type': 'text/plain',
13 | 'source': '1',
14 | 'model': model
15 | }
16 | response = requests.request("POST", url, headers=headers, data=payload)
17 | j = response.text.replace(' ', '').replace('\n', '').replace('\t', '')
18 | pattern = re.compile(r'\[\[(.*?)\]\]')
19 | matches = pattern.findall(j)
20 | print(matches)
21 | # 38%2C43%7C105%2C50%7C174%2C30%7C245%2C50%7C314%2C34
22 | # 38,43|105,50|174,30|245,50|314,34
23 | # 174,40|314,41
24 | matches = matches[0].replace('],[', '%7C').replace(',', '%2C')
25 | return matches
26 |
--------------------------------------------------------------------------------
/fun/com.py:
--------------------------------------------------------------------------------
1 | import time
2 | import re
3 |
4 | # 获取时间戳
5 | def get_time():
6 | return int(round(time.time() * 1000))
7 |
8 | # 取中间文本
9 | def GetIntermediateText(text, start, end):
10 | print(text)
11 | pattern = re.escape(start) + '(.*?)' + re.escape(end)
12 | match = re.search(pattern, text)
13 | if match:
14 | return match.group(1)
15 | return ''
16 |
--------------------------------------------------------------------------------
/image/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytt447735/automation/df1a196c201249464f874c5caad750325896e87e/image/1.png
--------------------------------------------------------------------------------
/image/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ytt447735/automation/df1a196c201249464f874c5caad750325896e87e/image/3.png
--------------------------------------------------------------------------------
/notify.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # _*_ coding:utf-8 _*_
3 | import base64
4 | import hashlib
5 | import hmac
6 | import json
7 | import os
8 | import re
9 | import threading
10 | import time
11 | import urllib.parse
12 | import smtplib
13 | from email.mime.text import MIMEText
14 | from email.header import Header
15 | from email.utils import formataddr
16 |
17 | import requests
18 |
19 | # 原先的 print 函数和主线程的锁
20 | _print = print
21 | mutex = threading.Lock()
22 |
23 |
24 | # 定义新的 print 函数
25 | def print(text, *args, **kw):
26 | """
27 | 使输出有序进行,不出现多线程同一时间输出导致错乱的问题。
28 | """
29 | with mutex:
30 | _print(text, *args, **kw)
31 |
32 |
33 | # 通知服务
34 | # fmt: off
35 | push_config = {
36 | 'HITOKOTO': False, # 启用一言(随机句子)
37 |
38 | 'BARK_PUSH': '', # bark IP 或设备码,例:https://api.day.app/DxHcxxxxxRxxxxxxcm/
39 | 'BARK_ARCHIVE': '', # bark 推送是否存档
40 | 'BARK_GROUP': '', # bark 推送分组
41 | 'BARK_SOUND': '', # bark 推送声音
42 | 'BARK_ICON': '', # bark 推送图标
43 | 'BARK_LEVEL': '', # bark 推送时效性
44 | 'BARK_URL': '', # bark 推送跳转URL
45 |
46 | 'CONSOLE': True, # 控制台输出
47 |
48 | 'DD_BOT_SECRET': '', # 钉钉机器人的 DD_BOT_SECRET
49 | 'DD_BOT_TOKEN': '', # 钉钉机器人的 DD_BOT_TOKEN
50 |
51 | 'FSKEY': '', # 飞书机器人的 FSKEY
52 |
53 | 'GOBOT_URL': '', # go-cqhttp
54 | # 推送到个人QQ:http://127.0.0.1/send_private_msg
55 | # 群:http://127.0.0.1/send_group_msg
56 | 'GOBOT_QQ': '', # go-cqhttp 的推送群或用户
57 | # GOBOT_URL 设置 /send_private_msg 时填入 user_id=个人QQ
58 | # /send_group_msg 时填入 group_id=QQ群
59 | 'GOBOT_TOKEN': '', # go-cqhttp 的 access_token
60 |
61 | 'GOTIFY_URL': '', # gotify地址,如https://push.example.de:8080
62 | 'GOTIFY_TOKEN': '', # gotify的消息应用token
63 | 'GOTIFY_PRIORITY': 0, # 推送消息优先级,默认为0
64 |
65 | 'IGOT_PUSH_KEY': '', # iGot 聚合推送的 IGOT_PUSH_KEY
66 |
67 | 'PUSH_KEY': '', # server 酱的 PUSH_KEY,兼容旧版与 Turbo 版
68 |
69 | 'DEER_KEY': '', # PushDeer 的 PUSHDEER_KEY
70 | 'DEER_URL': '', # PushDeer 的 PUSHDEER_URL
71 |
72 | 'CHAT_URL': '', # synology chat url
73 | 'CHAT_TOKEN': '', # synology chat token
74 |
75 | 'PUSH_PLUS_TOKEN': '', # push+ 微信推送的用户令牌
76 | 'PUSH_PLUS_USER': '', # push+ 微信推送的群组编码
77 |
78 | 'QMSG_KEY': '', # qmsg 酱的 QMSG_KEY
79 | 'QMSG_TYPE': '', # qmsg 酱的 QMSG_TYPE
80 |
81 | 'QYWX_ORIGIN': '', # 企业微信代理地址
82 |
83 | 'QYWX_AM': '', # 企业微信应用
84 |
85 | 'QYWX_KEY': '', # 企业微信机器人
86 |
87 | 'TG_BOT_TOKEN': '', # tg 机器人的 TG_BOT_TOKEN,例:1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ
88 | 'TG_USER_ID': '', # tg 机器人的 TG_USER_ID,例:1434078534
89 | 'TG_API_HOST': '', # tg 代理 api
90 | 'TG_PROXY_AUTH': '', # tg 代理认证参数
91 | 'TG_PROXY_HOST': '', # tg 机器人的 TG_PROXY_HOST
92 | 'TG_PROXY_PORT': '', # tg 机器人的 TG_PROXY_PORT
93 |
94 | 'AIBOTK_KEY': '', # 智能微秘书 个人中心的apikey 文档地址:http://wechat.aibotk.com/docs/about
95 | 'AIBOTK_TYPE': '', # 智能微秘书 发送目标 room 或 contact
96 | 'AIBOTK_NAME': '', # 智能微秘书 发送群名 或者好友昵称和type要对应好
97 |
98 | 'SMTP_SERVER': '', # SMTP 发送邮件服务器,形如 smtp.exmail.qq.com:465
99 | 'SMTP_SSL': 'false', # SMTP 发送邮件服务器是否使用 SSL,填写 true 或 false
100 | 'SMTP_EMAIL': '', # SMTP 收发件邮箱,通知将会由自己发给自己
101 | 'SMTP_PASSWORD': '', # SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定
102 | 'SMTP_NAME': '', # SMTP 收发件人姓名,可随意填写
103 |
104 | 'PUSHME_KEY': '', # PushMe 酱的 PUSHME_KEY
105 |
106 | 'CHRONOCAT_QQ': '', # qq号
107 | 'CHRONOCAT_TOKEN': '', # CHRONOCAT 的token
108 | 'CHRONOCAT_URL': '', # CHRONOCAT的url地址
109 |
110 | 'WEBHOOK_URL': '', # 自定义通知 请求地址
111 | 'WEBHOOK_BODY': '', # 自定义通知 请求体
112 | 'WEBHOOK_HEADERS': '', # 自定义通知 请求头
113 | 'WEBHOOK_METHOD': '', # 自定义通知 请求方法
114 | 'WEBHOOK_CONTENT_TYPE': '', # 自定义通知 content-type
115 |
116 | 'SYNOLOG_CHAT24_URL':'',
117 | }
118 | notify_function = []
119 | # fmt: on
120 |
121 | # 首先读取 面板变量 或者 github action 运行变量
122 | for k in push_config:
123 | if os.getenv(k):
124 | v = os.getenv(k)
125 | push_config[k] = v
126 |
127 |
128 | def bark(title: str, content: str) -> None:
129 | """
130 | 使用 bark 推送消息。
131 | """
132 | if not push_config.get("BARK_PUSH"):
133 | print("bark 服务的 BARK_PUSH 未设置!!\n取消推送")
134 | return
135 | print("bark 服务启动")
136 |
137 | if push_config.get("BARK_PUSH").startswith("http"):
138 | url = f'{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
139 | else:
140 | url = f'https://api.day.app/{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
141 |
142 | bark_params = {
143 | "BARK_ARCHIVE": "isArchive",
144 | "BARK_GROUP": "group",
145 | "BARK_SOUND": "sound",
146 | "BARK_ICON": "icon",
147 | "BARK_LEVEL": "level",
148 | "BARK_URL": "url",
149 | }
150 | params = ""
151 | for pair in filter(
152 | lambda pairs: pairs[0].startswith("BARK_")
153 | and pairs[0] != "BARK_PUSH"
154 | and pairs[1]
155 | and bark_params.get(pairs[0]),
156 | push_config.items(),
157 | ):
158 | params += f"{bark_params.get(pair[0])}={pair[1]}&"
159 | if params:
160 | url = url + "?" + params.rstrip("&")
161 | response = requests.get(url).json()
162 |
163 | if response["code"] == 200:
164 | print("bark 推送成功!")
165 | else:
166 | print("bark 推送失败!")
167 |
168 |
169 | def console(title: str, content: str) -> None:
170 | """
171 | 使用 控制台 推送消息。
172 | """
173 | print(f"{title}\n\n{content}")
174 |
175 |
176 | def dingding_bot(title: str, content: str) -> None:
177 | """
178 | 使用 钉钉机器人 推送消息。
179 | """
180 | if not push_config.get("DD_BOT_SECRET") or not push_config.get("DD_BOT_TOKEN"):
181 | print("钉钉机器人 服务的 DD_BOT_SECRET 或者 DD_BOT_TOKEN 未设置!!\n取消推送")
182 | return
183 | print("钉钉机器人 服务启动")
184 |
185 | timestamp = str(round(time.time() * 1000))
186 | secret_enc = push_config.get("DD_BOT_SECRET").encode("utf-8")
187 | string_to_sign = "{}\n{}".format(timestamp, push_config.get("DD_BOT_SECRET"))
188 | string_to_sign_enc = string_to_sign.encode("utf-8")
189 | hmac_code = hmac.new(
190 | secret_enc, string_to_sign_enc, digestmod=hashlib.sha256
191 | ).digest()
192 | sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
193 | url = f'https://oapi.dingtalk.com/robot/send?access_token={push_config.get("DD_BOT_TOKEN")}×tamp={timestamp}&sign={sign}'
194 | headers = {"Content-Type": "application/json;charset=utf-8"}
195 | data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
196 | response = requests.post(
197 | url=url, data=json.dumps(data), headers=headers, timeout=15
198 | ).json()
199 |
200 | if not response["errcode"]:
201 | print("钉钉机器人 推送成功!")
202 | else:
203 | print("钉钉机器人 推送失败!")
204 |
205 |
206 | def feishu_bot(title: str, content: str) -> None:
207 | """
208 | 使用 飞书机器人 推送消息。
209 | """
210 | if not push_config.get("FSKEY"):
211 | print("飞书 服务的 FSKEY 未设置!!\n取消推送")
212 | return
213 | print("飞书 服务启动")
214 |
215 | url = f'https://open.feishu.cn/open-apis/bot/v2/hook/{push_config.get("FSKEY")}'
216 | data = {"msg_type": "text", "content": {"text": f"{title}\n\n{content}"}}
217 | response = requests.post(url, data=json.dumps(data)).json()
218 |
219 | if response.get("StatusCode") == 0:
220 | print("飞书 推送成功!")
221 | else:
222 | print("飞书 推送失败!错误信息如下:\n", response)
223 |
224 |
225 | def go_cqhttp(title: str, content: str) -> None:
226 | """
227 | 使用 go_cqhttp 推送消息。
228 | """
229 | if not push_config.get("GOBOT_URL") or not push_config.get("GOBOT_QQ"):
230 | print("go-cqhttp 服务的 GOBOT_URL 或 GOBOT_QQ 未设置!!\n取消推送")
231 | return
232 | print("go-cqhttp 服务启动")
233 |
234 | url = f'{push_config.get("GOBOT_URL")}?access_token={push_config.get("GOBOT_TOKEN")}&{push_config.get("GOBOT_QQ")}&message=标题:{title}\n内容:{content}'
235 | response = requests.get(url).json()
236 |
237 | if response["status"] == "ok":
238 | print("go-cqhttp 推送成功!")
239 | else:
240 | print("go-cqhttp 推送失败!")
241 |
242 |
243 | def gotify(title: str, content: str) -> None:
244 | """
245 | 使用 gotify 推送消息。
246 | """
247 | if not push_config.get("GOTIFY_URL") or not push_config.get("GOTIFY_TOKEN"):
248 | print("gotify 服务的 GOTIFY_URL 或 GOTIFY_TOKEN 未设置!!\n取消推送")
249 | return
250 | print("gotify 服务启动")
251 |
252 | url = f'{push_config.get("GOTIFY_URL")}/message?token={push_config.get("GOTIFY_TOKEN")}'
253 | data = {
254 | "title": title,
255 | "message": content,
256 | "priority": push_config.get("GOTIFY_PRIORITY"),
257 | }
258 | response = requests.post(url, data=data).json()
259 |
260 | if response.get("id"):
261 | print("gotify 推送成功!")
262 | else:
263 | print("gotify 推送失败!")
264 |
265 |
266 | def iGot(title: str, content: str) -> None:
267 | """
268 | 使用 iGot 推送消息。
269 | """
270 | if not push_config.get("IGOT_PUSH_KEY"):
271 | print("iGot 服务的 IGOT_PUSH_KEY 未设置!!\n取消推送")
272 | return
273 | print("iGot 服务启动")
274 |
275 | url = f'https://push.hellyw.com/{push_config.get("IGOT_PUSH_KEY")}'
276 | data = {"title": title, "content": content}
277 | headers = {"Content-Type": "application/x-www-form-urlencoded"}
278 | response = requests.post(url, data=data, headers=headers).json()
279 |
280 | if response["ret"] == 0:
281 | print("iGot 推送成功!")
282 | else:
283 | print(f'iGot 推送失败!{response["errMsg"]}')
284 |
285 |
286 | def serverJ(title: str, content: str) -> None:
287 | """
288 | 通过 serverJ 推送消息。
289 | """
290 | if not push_config.get("PUSH_KEY"):
291 | print("serverJ 服务的 PUSH_KEY 未设置!!\n取消推送")
292 | return
293 | print("serverJ 服务启动")
294 |
295 | data = {"text": title, "desp": content.replace("\n", "\n\n")}
296 | if push_config.get("PUSH_KEY").find("SCT") != -1:
297 | url = f'https://sctapi.ftqq.com/{push_config.get("PUSH_KEY")}.send'
298 | else:
299 | url = f'https://sc.ftqq.com/{push_config.get("PUSH_KEY")}.send'
300 | response = requests.post(url, data=data).json()
301 |
302 | if response.get("errno") == 0 or response.get("code") == 0:
303 | print("serverJ 推送成功!")
304 | else:
305 | print(f'serverJ 推送失败!错误码:{response["message"]}')
306 |
307 |
308 | def pushdeer(title: str, content: str) -> None:
309 | """
310 | 通过PushDeer 推送消息
311 | """
312 | if not push_config.get("DEER_KEY"):
313 | print("PushDeer 服务的 DEER_KEY 未设置!!\n取消推送")
314 | return
315 | print("PushDeer 服务启动")
316 | data = {
317 | "text": title,
318 | "desp": content,
319 | "type": "markdown",
320 | "pushkey": push_config.get("DEER_KEY"),
321 | }
322 | url = "https://api2.pushdeer.com/message/push"
323 | if push_config.get("DEER_URL"):
324 | url = push_config.get("DEER_URL")
325 |
326 | response = requests.post(url, data=data).json()
327 |
328 | if len(response.get("content").get("result")) > 0:
329 | print("PushDeer 推送成功!")
330 | else:
331 | print("PushDeer 推送失败!错误信息:", response)
332 |
333 |
334 | def chat(title: str, content: str) -> None:
335 | """
336 | 通过Chat 推送消息
337 | """
338 | if not push_config.get("CHAT_URL") or not push_config.get("CHAT_TOKEN"):
339 | print("chat 服务的 CHAT_URL或CHAT_TOKEN 未设置!!\n取消推送")
340 | return
341 | print("chat 服务启动")
342 | data = "payload=" + json.dumps({"text": title + "\n" + content})
343 | url = push_config.get("CHAT_URL") + push_config.get("CHAT_TOKEN")
344 | response = requests.post(url, data=data)
345 |
346 | if response.status_code == 200:
347 | print("Chat 推送成功!")
348 | else:
349 | print("Chat 推送失败!错误信息:", response)
350 |
351 |
352 | def pushplus_bot(title: str, content: str) -> None:
353 | """
354 | 通过 push+ 推送消息。
355 | """
356 | if not push_config.get("PUSH_PLUS_TOKEN"):
357 | print("PUSHPLUS 服务的 PUSH_PLUS_TOKEN 未设置!!\n取消推送")
358 | return
359 | print("PUSHPLUS 服务启动")
360 |
361 | url = "http://www.pushplus.plus/send"
362 | data = {
363 | "token": push_config.get("PUSH_PLUS_TOKEN"),
364 | "title": title,
365 | "content": content,
366 | "topic": push_config.get("PUSH_PLUS_USER"),
367 | }
368 | body = json.dumps(data).encode(encoding="utf-8")
369 | headers = {"Content-Type": "application/json"}
370 | response = requests.post(url=url, data=body, headers=headers).json()
371 |
372 | if response["code"] == 200:
373 | print("PUSHPLUS 推送成功!")
374 |
375 | else:
376 | url_old = "http://pushplus.hxtrip.com/send"
377 | headers["Accept"] = "application/json"
378 | response = requests.post(url=url_old, data=body, headers=headers).json()
379 |
380 | if response["code"] == 200:
381 | print("PUSHPLUS(hxtrip) 推送成功!")
382 |
383 | else:
384 | print("PUSHPLUS 推送失败!")
385 |
386 |
387 | def qmsg_bot(title: str, content: str) -> None:
388 | """
389 | 使用 qmsg 推送消息。
390 | """
391 | if not push_config.get("QMSG_KEY") or not push_config.get("QMSG_TYPE"):
392 | print("qmsg 的 QMSG_KEY 或者 QMSG_TYPE 未设置!!\n取消推送")
393 | return
394 | print("qmsg 服务启动")
395 |
396 | url = f'https://qmsg.zendee.cn/{push_config.get("QMSG_TYPE")}/{push_config.get("QMSG_KEY")}'
397 | payload = {"msg": f'{title}\n\n{content.replace("----", "-")}'.encode("utf-8")}
398 | response = requests.post(url=url, params=payload).json()
399 |
400 | if response["code"] == 0:
401 | print("qmsg 推送成功!")
402 | else:
403 | print(f'qmsg 推送失败!{response["reason"]}')
404 |
405 |
406 | def wecom_app(title: str, content: str) -> None:
407 | """
408 | 通过 企业微信 APP 推送消息。
409 | """
410 | if not push_config.get("QYWX_AM"):
411 | print("QYWX_AM 未设置!!\n取消推送")
412 | return
413 | QYWX_AM_AY = re.split(",", push_config.get("QYWX_AM"))
414 | if 4 < len(QYWX_AM_AY) > 5:
415 | print("QYWX_AM 设置错误!!\n取消推送")
416 | return
417 | print("企业微信 APP 服务启动")
418 |
419 | corpid = QYWX_AM_AY[0]
420 | corpsecret = QYWX_AM_AY[1]
421 | touser = QYWX_AM_AY[2]
422 | agentid = QYWX_AM_AY[3]
423 | try:
424 | media_id = QYWX_AM_AY[4]
425 | except IndexError:
426 | media_id = ""
427 | wx = WeCom(corpid, corpsecret, agentid)
428 | # 如果没有配置 media_id 默认就以 text 方式发送
429 | if not media_id:
430 | message = title + "\n\n" + content
431 | response = wx.send_text(message, touser)
432 | else:
433 | response = wx.send_mpnews(title, content, media_id, touser)
434 |
435 | if response == "ok":
436 | print("企业微信推送成功!")
437 | else:
438 | print("企业微信推送失败!错误信息如下:\n", response)
439 |
440 |
441 | class WeCom:
442 | def __init__(self, corpid, corpsecret, agentid):
443 | self.CORPID = corpid
444 | self.CORPSECRET = corpsecret
445 | self.AGENTID = agentid
446 | self.ORIGIN = "https://qyapi.weixin.qq.com"
447 | if push_config.get("QYWX_ORIGIN"):
448 | self.ORIGIN = push_config.get("QYWX_ORIGIN")
449 |
450 | def get_access_token(self):
451 | url = f"{self.ORIGIN}/cgi-bin/gettoken"
452 | values = {
453 | "corpid": self.CORPID,
454 | "corpsecret": self.CORPSECRET,
455 | }
456 | req = requests.post(url, params=values)
457 | data = json.loads(req.text)
458 | return data["access_token"]
459 |
460 | def send_text(self, message, touser="@all"):
461 | send_url = (
462 | f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
463 | )
464 | send_values = {
465 | "touser": touser,
466 | "msgtype": "text",
467 | "agentid": self.AGENTID,
468 | "text": {"content": message},
469 | "safe": "0",
470 | }
471 | send_msges = bytes(json.dumps(send_values), "utf-8")
472 | respone = requests.post(send_url, send_msges)
473 | respone = respone.json()
474 | return respone["errmsg"]
475 |
476 | def send_mpnews(self, title, message, media_id, touser="@all"):
477 | send_url = (
478 | f"{self.ORIGIN}/cgi-bin/message/send?access_token={self.get_access_token()}"
479 | )
480 | send_values = {
481 | "touser": touser,
482 | "msgtype": "mpnews",
483 | "agentid": self.AGENTID,
484 | "mpnews": {
485 | "articles": [
486 | {
487 | "title": title,
488 | "thumb_media_id": media_id,
489 | "author": "Author",
490 | "content_source_url": "",
491 | "content": message.replace("\n", "
"),
492 | "digest": message,
493 | }
494 | ]
495 | },
496 | }
497 | send_msges = bytes(json.dumps(send_values), "utf-8")
498 | respone = requests.post(send_url, send_msges)
499 | respone = respone.json()
500 | return respone["errmsg"]
501 |
502 |
503 | def wecom_bot(title: str, content: str) -> None:
504 | """
505 | 通过 企业微信机器人 推送消息。
506 | """
507 | if not push_config.get("QYWX_KEY"):
508 | print("企业微信机器人 服务的 QYWX_KEY 未设置!!\n取消推送")
509 | return
510 | print("企业微信机器人服务启动")
511 |
512 | origin = "https://qyapi.weixin.qq.com"
513 | if push_config.get("QYWX_ORIGIN"):
514 | origin = push_config.get("QYWX_ORIGIN")
515 |
516 | url = f"{origin}/cgi-bin/webhook/send?key={push_config.get('QYWX_KEY')}"
517 | headers = {"Content-Type": "application/json;charset=utf-8"}
518 | data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
519 | response = requests.post(
520 | url=url, data=json.dumps(data), headers=headers, timeout=15
521 | ).json()
522 |
523 | if response["errcode"] == 0:
524 | print("企业微信机器人推送成功!")
525 | else:
526 | print("企业微信机器人推送失败!")
527 |
528 |
529 | def telegram_bot(title: str, content: str) -> None:
530 | """
531 | 使用 telegram 机器人 推送消息。
532 | """
533 | if not push_config.get("TG_BOT_TOKEN") or not push_config.get("TG_USER_ID"):
534 | print("tg 服务的 bot_token 或者 user_id 未设置!!\n取消推送")
535 | return
536 | print("tg 服务启动")
537 |
538 | if push_config.get("TG_API_HOST"):
539 | url = f"https://{push_config.get('TG_API_HOST')}/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
540 | else:
541 | url = (
542 | f"https://api.telegram.org/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
543 | )
544 | headers = {"Content-Type": "application/x-www-form-urlencoded"}
545 | payload = {
546 | "chat_id": str(push_config.get("TG_USER_ID")),
547 | "text": f"{title}\n\n{content}",
548 | "disable_web_page_preview": "true",
549 | }
550 | proxies = None
551 | if push_config.get("TG_PROXY_HOST") and push_config.get("TG_PROXY_PORT"):
552 | if push_config.get("TG_PROXY_AUTH") is not None and "@" not in push_config.get(
553 | "TG_PROXY_HOST"
554 | ):
555 | push_config["TG_PROXY_HOST"] = (
556 | push_config.get("TG_PROXY_AUTH")
557 | + "@"
558 | + push_config.get("TG_PROXY_HOST")
559 | )
560 | proxyStr = "http://{}:{}".format(
561 | push_config.get("TG_PROXY_HOST"), push_config.get("TG_PROXY_PORT")
562 | )
563 | proxies = {"http": proxyStr, "https": proxyStr}
564 | response = requests.post(
565 | url=url, headers=headers, params=payload, proxies=proxies
566 | ).json()
567 |
568 | if response["ok"]:
569 | print("tg 推送成功!")
570 | else:
571 | print("tg 推送失败!")
572 |
573 |
574 | def aibotk(title: str, content: str) -> None:
575 | """
576 | 使用 智能微秘书 推送消息。
577 | """
578 | if (
579 | not push_config.get("AIBOTK_KEY")
580 | or not push_config.get("AIBOTK_TYPE")
581 | or not push_config.get("AIBOTK_NAME")
582 | ):
583 | print("智能微秘书 的 AIBOTK_KEY 或者 AIBOTK_TYPE 或者 AIBOTK_NAME 未设置!!\n取消推送")
584 | return
585 | print("智能微秘书 服务启动")
586 |
587 | if push_config.get("AIBOTK_TYPE") == "room":
588 | url = "https://api-bot.aibotk.com/openapi/v1/chat/room"
589 | data = {
590 | "apiKey": push_config.get("AIBOTK_KEY"),
591 | "roomName": push_config.get("AIBOTK_NAME"),
592 | "message": {"type": 1, "content": f"【青龙快讯】\n\n{title}\n{content}"},
593 | }
594 | else:
595 | url = "https://api-bot.aibotk.com/openapi/v1/chat/contact"
596 | data = {
597 | "apiKey": push_config.get("AIBOTK_KEY"),
598 | "name": push_config.get("AIBOTK_NAME"),
599 | "message": {"type": 1, "content": f"【青龙快讯】\n\n{title}\n{content}"},
600 | }
601 | body = json.dumps(data).encode(encoding="utf-8")
602 | headers = {"Content-Type": "application/json"}
603 | response = requests.post(url=url, data=body, headers=headers).json()
604 | print(response)
605 | if response["code"] == 0:
606 | print("智能微秘书 推送成功!")
607 | else:
608 | print(f'智能微秘书 推送失败!{response["error"]}')
609 |
610 |
611 | def smtp(title: str, content: str) -> None:
612 | """
613 | 使用 SMTP 邮件 推送消息。
614 | """
615 | if (
616 | not push_config.get("SMTP_SERVER")
617 | or not push_config.get("SMTP_SSL")
618 | or not push_config.get("SMTP_EMAIL")
619 | or not push_config.get("SMTP_PASSWORD")
620 | or not push_config.get("SMTP_NAME")
621 | ):
622 | print(
623 | "SMTP 邮件 的 SMTP_SERVER 或者 SMTP_SSL 或者 SMTP_EMAIL 或者 SMTP_PASSWORD 或者 SMTP_NAME 未设置!!\n取消推送"
624 | )
625 | return
626 | print("SMTP 邮件 服务启动")
627 |
628 | message = MIMEText(content, "plain", "utf-8")
629 | message["From"] = formataddr(
630 | (
631 | Header(push_config.get("SMTP_NAME"), "utf-8").encode(),
632 | push_config.get("SMTP_EMAIL"),
633 | )
634 | )
635 | message["To"] = formataddr(
636 | (
637 | Header(push_config.get("SMTP_NAME"), "utf-8").encode(),
638 | push_config.get("SMTP_EMAIL"),
639 | )
640 | )
641 | message["Subject"] = Header(title, "utf-8")
642 |
643 | try:
644 | smtp_server = (
645 | smtplib.SMTP_SSL(push_config.get("SMTP_SERVER"))
646 | if push_config.get("SMTP_SSL") == "true"
647 | else smtplib.SMTP(push_config.get("SMTP_SERVER"))
648 | )
649 | smtp_server.login(
650 | push_config.get("SMTP_EMAIL"), push_config.get("SMTP_PASSWORD")
651 | )
652 | smtp_server.sendmail(
653 | push_config.get("SMTP_EMAIL"),
654 | push_config.get("SMTP_EMAIL"),
655 | message.as_bytes(),
656 | )
657 | smtp_server.close()
658 | print("SMTP 邮件 推送成功!")
659 | except Exception as e:
660 | print(f"SMTP 邮件 推送失败!{e}")
661 |
662 |
663 | def pushme(title: str, content: str) -> None:
664 | """
665 | 使用 PushMe 推送消息。
666 | """
667 | if not push_config.get("PUSHME_KEY"):
668 | print("PushMe 服务的 PUSHME_KEY 未设置!!\n取消推送")
669 | return
670 | print("PushMe 服务启动")
671 |
672 | url = f'https://push.i-i.me/?push_key={push_config.get("PUSHME_KEY")}'
673 | data = {
674 | "title": title,
675 | "content": content,
676 | }
677 | response = requests.post(url, data=data)
678 |
679 | if response.status_code == 200 and response.text == "success":
680 | print("PushMe 推送成功!")
681 | else:
682 | print(f"PushMe 推送失败!{response.status_code} {response.text}")
683 |
684 |
685 | def chronocat(title: str, content: str) -> None:
686 | """
687 | 使用 CHRONOCAT 推送消息。
688 | """
689 | if (
690 | not push_config.get("CHRONOCAT_URL")
691 | or not push_config.get("CHRONOCAT_QQ")
692 | or not push_config.get("CHRONOCAT_TOKEN")
693 | ):
694 | print("CHRONOCAT 服务的 CHRONOCAT_URL 或 CHRONOCAT_QQ 未设置!!\n取消推送")
695 | return
696 |
697 | print("CHRONOCAT 服务启动")
698 |
699 | user_ids = re.findall(r"user_id=(\d+)", push_config.get("CHRONOCAT_QQ"))
700 | group_ids = re.findall(r"group_id=(\d+)", push_config.get("CHRONOCAT_QQ"))
701 |
702 | url = f'{push_config.get("CHRONOCAT_URL")}/api/message/send'
703 | headers = {
704 | "Content-Type": "application/json",
705 | "Authorization": f'Bearer {push_config.get("CHRONOCAT_TOKEN")}',
706 | }
707 |
708 | for chat_type, ids in [(1, user_ids), (2, group_ids)]:
709 | if not ids:
710 | continue
711 | for chat_id in ids:
712 | data = {
713 | "peer": {"chatType": chat_type, "peerUin": chat_id},
714 | "elements": [
715 | {
716 | "elementType": 1,
717 | "textElement": {"content": f"{title}\n\n{content}"},
718 | }
719 | ],
720 | }
721 | response = requests.post(url, headers=headers, data=json.dumps(data))
722 | if response.status_code == 200:
723 | if chat_type == 1:
724 | print(f"QQ个人消息:{ids}推送成功!")
725 | else:
726 | print(f"QQ群消息:{ids}推送成功!")
727 | else:
728 | if chat_type == 1:
729 | print(f"QQ个人消息:{ids}推送失败!")
730 | else:
731 | print(f"QQ群消息:{ids}推送失败!")
732 |
733 |
734 | def parse_headers(headers):
735 | if not headers:
736 | return {}
737 |
738 | parsed = {}
739 | lines = headers.split("\n")
740 |
741 | for line in lines:
742 | i = line.find(":")
743 | if i == -1:
744 | continue
745 |
746 | key = line[:i].strip().lower()
747 | val = line[i + 1 :].strip()
748 | parsed[key] = parsed.get(key, "") + ", " + val if key in parsed else val
749 |
750 | return parsed
751 |
752 |
753 | def parse_body(body, content_type):
754 | if not body:
755 | return ""
756 |
757 | parsed = {}
758 | lines = body.split("\n")
759 |
760 | for line in lines:
761 | i = line.find(":")
762 | if i == -1:
763 | continue
764 |
765 | key = line[:i].strip().lower()
766 | val = line[i + 1 :].strip()
767 |
768 | if not key or key in parsed:
769 | continue
770 |
771 | try:
772 | json_value = json.loads(val)
773 | parsed[key] = json_value
774 | except:
775 | parsed[key] = val
776 |
777 | if content_type == "application/x-www-form-urlencoded":
778 | data = urlencode(parsed, doseq=True)
779 | return data
780 |
781 | if content_type == "application/json":
782 | data = json.dumps(parsed)
783 | return data
784 |
785 | return parsed
786 |
787 |
788 | def format_notify_content(url, body, title, content):
789 | if "$title" not in url and "$title" not in body:
790 | return {}
791 |
792 | formatted_url = url.replace("$title", urllib.parse.quote_plus(title)).replace(
793 | "$content", urllib.parse.quote_plus(content)
794 | )
795 | formatted_body = body.replace("$title", title).replace("$content", content)
796 |
797 | return formatted_url, formatted_body
798 |
799 |
800 | def custom_notify(title: str, content: str) -> None:
801 | """
802 | 通过 自定义通知 推送消息。
803 | """
804 | if not push_config.get("WEBHOOK_URL") or not push_config.get("WEBHOOK_METHOD"):
805 | print("自定义通知的 WEBHOOK_URL 或 WEBHOOK_METHOD 未设置!!\n取消推送")
806 | return
807 |
808 | print("自定义通知服务启动")
809 |
810 | WEBHOOK_URL = push_config.get("WEBHOOK_URL")
811 | WEBHOOK_METHOD = push_config.get("WEBHOOK_METHOD")
812 | WEBHOOK_CONTENT_TYPE = push_config.get("WEBHOOK_CONTENT_TYPE")
813 | WEBHOOK_BODY = push_config.get("WEBHOOK_BODY")
814 | WEBHOOK_HEADERS = push_config.get("WEBHOOK_HEADERS")
815 |
816 | formatUrl, formatBody = format_notify_content(
817 | WEBHOOK_URL, WEBHOOK_BODY, title, content
818 | )
819 |
820 | if not formatUrl and not formatBody:
821 | print("请求头或者请求体中必须包含 $title 和 $content")
822 | return
823 |
824 | headers = parse_headers(WEBHOOK_HEADERS)
825 | body = parse_body(formatBody, WEBHOOK_CONTENT_TYPE)
826 | response = requests.request(
827 | method=WEBHOOK_METHOD, url=formatUrl, headers=headers, timeout=15, data=body
828 | )
829 |
830 | if response.status_code == 200:
831 | print("自定义通知推送成功!")
832 | else:
833 | print(f"自定义通知推送失败!{response.status_code} {response.text}")
834 |
835 | def synolog_chat24(title: str, content: str) -> None:
836 | """
837 | 通过 群晖chat2.4 推送消息。
838 | """
839 | if not push_config.get("SYNOLOG_CHAT24_URL"):
840 | print("自定义通知的 SYNOLOG_CHAT24_URL 未设置!!\n取消推送")
841 | return
842 |
843 | print("自定义通知服务启动")
844 | data = '{"text": "'+content+'"}'
845 | SYNOLOG_CHAT24_URL = push_config.get("SYNOLOG_CHAT24_URL")
846 | body = {
847 | "payload":data.encode('utf-8')
848 | }
849 | response = requests.request(
850 | method='POST', url=SYNOLOG_CHAT24_URL, timeout=15, data=body
851 | )
852 | # print(body)
853 | # print(response.text)
854 | if response.status_code == 200:
855 | print("自定义通知推送成功!")
856 | else:
857 | print(f"自定义通知推送失败!{response.status_code} {response.text}")
858 |
859 | def one() -> str:
860 | """
861 | 获取一条一言。
862 | :return:
863 | """
864 | url = "https://v1.hitokoto.cn/"
865 | res = requests.get(url).json()
866 | return res["hitokoto"] + " ----" + res["from"]
867 |
868 |
869 | if push_config.get("BARK_PUSH"):
870 | notify_function.append(bark)
871 | if push_config.get("CONSOLE"):
872 | notify_function.append(console)
873 | if push_config.get("DD_BOT_TOKEN") and push_config.get("DD_BOT_SECRET"):
874 | notify_function.append(dingding_bot)
875 | if push_config.get("FSKEY"):
876 | notify_function.append(feishu_bot)
877 | if push_config.get("GOBOT_URL") and push_config.get("GOBOT_QQ"):
878 | notify_function.append(go_cqhttp)
879 | if push_config.get("GOTIFY_URL") and push_config.get("GOTIFY_TOKEN"):
880 | notify_function.append(gotify)
881 | if push_config.get("IGOT_PUSH_KEY"):
882 | notify_function.append(iGot)
883 | if push_config.get("PUSH_KEY"):
884 | notify_function.append(serverJ)
885 | if push_config.get("DEER_KEY"):
886 | notify_function.append(pushdeer)
887 | if push_config.get("CHAT_URL") and push_config.get("CHAT_TOKEN"):
888 | notify_function.append(chat)
889 | if push_config.get("PUSH_PLUS_TOKEN"):
890 | notify_function.append(pushplus_bot)
891 | if push_config.get("QMSG_KEY") and push_config.get("QMSG_TYPE"):
892 | notify_function.append(qmsg_bot)
893 | if push_config.get("QYWX_AM"):
894 | notify_function.append(wecom_app)
895 | if push_config.get("QYWX_KEY"):
896 | notify_function.append(wecom_bot)
897 | if push_config.get("TG_BOT_TOKEN") and push_config.get("TG_USER_ID"):
898 | notify_function.append(telegram_bot)
899 | if (
900 | push_config.get("AIBOTK_KEY")
901 | and push_config.get("AIBOTK_TYPE")
902 | and push_config.get("AIBOTK_NAME")
903 | ):
904 | notify_function.append(aibotk)
905 | if (
906 | push_config.get("SMTP_SERVER")
907 | and push_config.get("SMTP_SSL")
908 | and push_config.get("SMTP_EMAIL")
909 | and push_config.get("SMTP_PASSWORD")
910 | and push_config.get("SMTP_NAME")
911 | ):
912 | notify_function.append(smtp)
913 | if push_config.get("PUSHME_KEY"):
914 | notify_function.append(pushme)
915 | if (
916 | push_config.get("CHRONOCAT_URL")
917 | and push_config.get("CHRONOCAT_QQ")
918 | and push_config.get("CHRONOCAT_TOKEN")
919 | ):
920 | notify_function.append(chronocat)
921 | if push_config.get("WEBHOOK_URL") and push_config.get("WEBHOOK_METHOD"):
922 | notify_function.append(custom_notify)
923 |
924 | if push_config.get("SYNOLOG_CHAT24_URL"):
925 | notify_function.append(synolog_chat24)
926 |
927 | def send(title: str, content: str) -> None:
928 | if not content:
929 | print(f"{title} 推送内容为空!")
930 | return
931 |
932 | # 根据标题跳过一些消息推送,环境变量:SKIP_PUSH_TITLE 用回车分隔
933 | skipTitle = os.getenv("SKIP_PUSH_TITLE")
934 | if skipTitle:
935 | if title in re.split("\n", skipTitle):
936 | print(f"{title} 在SKIP_PUSH_TITLE环境变量内,跳过推送!")
937 | return
938 |
939 | hitokoto = push_config.get("HITOKOTO")
940 |
941 | text = one() if hitokoto else ""
942 | content += "\n\n" + text
943 |
944 | ts = [
945 | threading.Thread(target=mode, args=(title, content), name=mode.__name__)
946 | for mode in notify_function
947 | ]
948 | [t.start() for t in ts]
949 | [t.join() for t in ts]
950 |
951 |
952 | def main():
953 | send("title", "content")
954 |
955 |
956 | if __name__ == "__main__":
957 | main()
958 |
--------------------------------------------------------------------------------
/wpspc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | File: main.py(wps签到)
6 | Author: ytt447735
7 | cron: 0 8 * * *
8 | new Env('wps签到');
9 | Update: 2024/10/19
10 | """
11 | import os, notify
12 | import time
13 | import ujson
14 | import requests
15 | from io import BytesIO
16 | from fun import baidu, code
17 | import base64
18 | from io import BytesIO
19 |
20 | class wps:
21 | def __init__(self):
22 | self.Position = ["38%2C43", "105%2C50", "174%2C30", "245%2C50", "314%2C34"] # 位置信息
23 | self.ck = ''
24 | self.Referer = 'https://vip.wps.cn/spa/2021/wps-sign/?position=2020_vip_massing&client_pay_version=202301'
25 | self.Origin = 'https://vip.wps.cn'
26 | self.Log = ""
27 | self.code_fail=0
28 | self.userid = ''
29 |
30 | # 获取奖励信息
31 | def get_reward(self):
32 | url = "https://personal-act.wps.cn/wps_clock/v2"
33 |
34 | headers = {
35 | 'Origin': 'https://vip.wps.cn',
36 | 'Cookie': self.ck
37 | }
38 | response = requests.request("GET", url, headers=headers)
39 | # print(response.text)
40 | j = ujson.loads(response.text)
41 | if j["result"] == "ok":
42 | self.Log = self.Log + "📝签到日志:\n"
43 | for i, element in enumerate(j["data"]["list"]):
44 | if element["status"] == 1:
45 | status = "已领取"
46 | else:
47 | status = "未领取"
48 | jj = ujson.loads(element["ext"])
49 | # print(jj[0])
50 | self.Log = self.Log + f"⌚️第{i + 1}天🎁奖励{jj[0]['hour']}小时会员🎊{status}\n"
51 |
52 | # 获取用户信息
53 | def get_check(self):
54 | url = "https://account.wps.cn/p/auth/check"
55 |
56 | payload = {}
57 | headers = {
58 | 'Origin': 'https://vip.wps.cn',
59 | 'Cookie': self.ck,
60 | }
61 | response = requests.request("POST", url, headers=headers, data=payload)
62 | print(response.text)
63 | if "userid" in response.text:
64 | j = ujson.loads(response.text)
65 | if j["result"] == "ok":
66 | self.Log = self.Log + f"👤用户信息:{j['nickname']}\n"
67 | self.userid = j['userid']
68 | return True
69 | self.Log = self.Log + f"👤用户信息:获取失败\n"
70 | return False
71 |
72 | # 获取时间戳
73 | def get_time(self):
74 | return int(round(time.time() * 1000))
75 |
76 | # 处理验证码
77 | def code_processing(self):
78 | if self.userid == "":
79 | return False
80 | url = f"https://personal-act.wps.cn/vas_risk_system/v1/captcha/image?service_id=wps_clock&t={self.get_time()}&request_id=wps_clock_{self.userid}"
81 |
82 | # 构造请求头,包含Cookie信息
83 | headers = {'Cookie': self.ck}
84 |
85 | # 发送带有Cookie的HTTP请求获取图片
86 | response = requests.get(url, headers=headers)
87 | if response.status_code == 200:
88 | # 将图片内容转换为base64
89 | image_base64 = base64.b64encode(response.content).decode('utf-8')
90 | # 处理验证码
91 | if self.code_fail<=3:
92 | co = code.identify('pc', image_base64, '0')
93 | if self.code_fail>=3:
94 | co = code.identify('pc', image_base64, '1')
95 | if co == None:
96 | return False
97 | # return code
98 | return self.submit_code(co)
99 | else:
100 | self.code_fail = self.code_fail + 1
101 | return False
102 |
103 |
104 | # 提交验证码
105 | def submit_code(self, c):
106 | url = "https://personal-act.wps.cn/wps_clock/v2"
107 |
108 | payload = {
109 | 'double': '0',
110 | 'v': '11.1.0.10314',
111 | 'c': c
112 | }
113 | headers = {
114 | 'Cookie': self.ck
115 | }
116 | response = requests.request("POST", url, headers=headers, data=payload)
117 | print("submit_code:" + response.text)
118 | if 'ClockAgent' in response.text:
119 | self.Log = self.Log + "🙅你今日已经签到过了!\n"
120 | return True
121 | j = ujson.loads(response.text)
122 | if j["result"] == "ok":
123 | self.Log = self.Log + f"🎉今日签到成功,获得{j['data']['member']['hour']}小时会员\n"
124 | return True
125 | else:
126 | self.Log = self.Log + f"🥀今日签到失败,{j['msg']}\n"
127 | return False
128 |
129 | # 签到兑换
130 | def exchange(self, day):
131 | url = f"https://vipapi.wps.cn/wps_clock/v2/exchange?day={day}"
132 |
133 | headers = {
134 | 'Cookie': self.ck,
135 | 'Origin': self.Origin,
136 | 'Referer': self.Referer
137 | }
138 |
139 | response = requests.request("POST", url, headers=headers)
140 | print(response.text)
141 | j = ujson.loads(response.text)
142 | if j["result"] == "ok":
143 | self.Log = self.Log + f"🎉兑换成功,获得{day}天会员\n"
144 | return True
145 | else:
146 | self.Log = self.Log + f"🥀兑换失败,{j['msg']}\n"
147 | return False
148 |
149 | # 获取余额
150 | def get_balance(self):
151 | url = "https://vipapi.wps.cn/wps_clock/v2/user"
152 |
153 | payload = {}
154 | headers = {
155 | 'Referer': self.Referer,
156 | 'Origin': self.Origin,
157 | 'Cookie': self.ck
158 | }
159 | response = requests.request("GET", url, headers=headers, data=payload)
160 | print(response.text)
161 | j = ujson.loads(response.text)
162 | if j["result"] == "ok":
163 | total = j['data']['total'] // 3600
164 | cost = j['data']['cost'] // 3600
165 | self.Log = self.Log + f"🏦已使用额度:{ cost }小时({ cost // 24}天)\n"
166 | self.Log = self.Log + f"💰剩余额度:{total}小时({total // 24}天)\n"
167 | return j
168 |
169 | # 空间额度查询
170 | def get_space_quota(self):
171 | url = "https://vip.wps.cn/sign/mobile/v3/get_data"
172 | payload={}
173 | headers = {
174 | 'Referer': 'https://zt.wps.cn/spa/2019/vip_mobile_sign_v2/?csource=pc_cloud_personalpanel&position=pc_cloud_sign',
175 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36',
176 | 'Cookie': self.ck
177 | }
178 | response = requests.request("GET", url, headers=headers, data=payload)
179 | print(response.text)
180 | j = ujson.loads(response.text)
181 | if j["result"] == "ok":
182 | used = j['data']['spaces_info']['used']
183 | total = j['data']['spaces_info']['total']
184 | unit = j['data']['spaces_info']['unit']
185 | series_signed = j['data']['sign_status']['series_signed']
186 | total_signed = j['data']['sign_status']['total_signed']
187 | not_sign = j['data']['sign_status']['not_sign']
188 | self.Log = self.Log + f"☁️云空间:{ used }{ unit }/{ total }{ unit }\n"
189 | self.Log = self.Log + f"🪷连续签到:{ series_signed }天\n"
190 | self.Log = self.Log + f"⚡️累计签到:{ total_signed }天\n"
191 | self.Log = self.Log + "📝签到日志:\n"
192 | normal_list = j['data']["reward_list"]["space"]["normal"]
193 | # 循环输出normal数组,带循环序号
194 | for index, value in enumerate(normal_list, start=1):
195 | self.Log = self.Log + f"⌚️第{index}天🎁奖励{ value }M\n"
196 |
197 |
198 |
199 | # 空间验证码处理
200 | def space_code_processing(self):
201 | url = f"https://vip.wps.cn/checkcode/signin/captcha.png?platform=8&encode=0&img_witdh=336&img_height=84.48&v={self.get_time()}"
202 | payload={}
203 | headers = {
204 | 'Referer': 'https://zt.wps.cn/spa/2019/vip_mobile_sign_v2/?csource=pc_cloud_personalpanel&position=pc_cloud_sign',
205 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36',
206 | 'Cookie': self.ck
207 | }
208 | response = requests.request("GET", url, headers=headers, data=payload)
209 | # print(response.text)
210 | if response.status_code == 200:
211 | # 将图片内容转换为base64
212 | image_base64 = base64.b64encode(response.content).decode('utf-8')
213 | # 处理验证码
214 | co = code.identify('space',image_base64, '0')
215 | # return
216 | return self.submit_space(co)
217 | else:
218 | return None
219 |
220 |
221 | # 空间签到
222 | def submit_space(self, c):
223 | url = f"https://vip.wps.cn/sign/v2?platform=8&captcha_pos={c}&img_witdh=336&img_height=84.48"
224 | payload={}
225 | headers = {
226 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36',
227 | 'Referer': 'https://zt.wps.cn/spa/2019/vip_mobile_sign_v2/?csource=pc_cloud_personalpanel&position=pc_cloud_sign',
228 | 'Cookie': self.ck
229 | }
230 | response = requests.request("POST", url, headers=headers, data=payload)
231 | print(response.text)
232 | if "10003" in response.text:
233 | self.Log = self.Log + f"🙅你今日已经空间已经签到过了!\n"
234 | return True
235 | j = ujson.loads(response.text)
236 | if j["result"] == "ok":
237 | self.Log = self.Log + f"🎉今日空间签到成功!\n"
238 | return True
239 | else:
240 | self.Log = self.Log + f"🥀今日空间签到失败,{j['msg']}\n"
241 | return False
242 |
243 |
244 | # 新增日志
245 | def set_log(self,text):
246 | self.Log = self.Log + text
247 |
248 |
249 | # 获取日志
250 | def get_log(self):
251 | # return self.Log.replace("\n","\r\n")
252 | return self.Log
253 |
254 |
255 | def run(self):
256 | wps_pc = os.getenv("wps_pc")
257 | if not wps_pc:
258 | notify.send("WPS_PC",'🙃wps PC CK 变量未设置')
259 | print('🙃wps PC CK 变量未设置')
260 | exit()
261 | wps_pc_list = wps_pc.split('&')
262 | print("-------------------总共" + str(int(len(wps_pc_list))) + "个wps_PC CK-------------------")
263 | for mt_token in wps_pc_list:
264 | # try:
265 | self.ck = mt_token
266 | self.set_log("\n--------PC打卡--------\n")
267 | if not self.get_check():
268 | self.set_log(mt_token+" CK失效了\n")
269 | continue
270 | i = 0
271 | while True:
272 | i = i + 1
273 | if self.code_processing():
274 | print("第" + str(i + 1) + "次尝试签到成功")
275 | break
276 | else:
277 | print("第" + str(i + 1) + "次尝试签到失败")
278 | time.sleep(2)
279 | self.get_reward() # 获取奖励信息
280 | self.get_balance() # 获取余额
281 | # 开始空间处理
282 | self.set_log("\n--------云空间--------\n")
283 | i = 0
284 | while True:
285 | i = i + 1
286 | if self.space_code_processing():
287 | print("第" + str(i + 1) + "次尝试空间签到成功")
288 | break
289 | else:
290 | print("第" + str(i + 1) + "次尝试空间签到失败")
291 | time.sleep(2)
292 | self.get_space_quota() #获取空间额度
293 | print("📝签到日志:")
294 | print(self.get_log())
295 | notify.send("WPS_PC", self.get_log())
296 | # except Exception as e:
297 | # print("出错了!详细错误👇错误CK👉" + mt_token)
298 | # print(e)
299 | # notify.send("WPS_PC", "出错了!详细错误👇错误CK👉" + mt_token +"\n错误内容:" + str(e))
300 |
301 |
302 | if __name__ == '__main__':
303 | r = wps()
304 | r.run()
305 |
--------------------------------------------------------------------------------