Initial Qinglong script classification corpus

This commit is contained in:
Hermes Agent
2026-05-23 18:48:48 +00:00
commit 5b4854515c
32 changed files with 15496 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
# runtime/cache
metadata/collector_cache.json
__pycache__/
*.pyc
# keep generated indexes and scripts tracked

25
INDEX.csv Normal file
View File

@@ -0,0 +1,25 @@
category,project,filename,sha256,source_platform,source_repo,source_path,source_url,raw_url,uploaded_at,saved_path,auth_type,platform_type,evidence
APP版/抓包,content,2026-05-19_content_45c4e352.js,45c4e3523ff88ee080e76c2c8b635c4a14657f9f97fa395d368b9bccf09b4bca,GitHub,huwangkeji/juejin_checkin,juejin-extension/content.js,https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/content.js,https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/content.js,2026-05-19T14:34:11Z,脚本库/APP版/抓包/content/2026-05-19_content_45c4e352.js,抓包,APP版,cookie/token/authorization/header
web版/抓包,"'Cookie',_env_'JUEJIN_COOKIE',_isLong_true_},",2026-05-19_popup_0a4d4983.js,0a4d49831a306fa984f62b0d1b3f26f7fc1274a625d08b5f4622ba94121b8469,GitHub,huwangkeji/juejin_checkin,juejin-extension/popup.js,https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/popup.js,https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/popup.js,2026-05-19T14:34:11Z,"脚本库/web版/抓包/'Cookie',_env_'JUEJIN_COOKIE',_isLong_true_},/2026-05-19_popup_0a4d4983.js",抓包,web版,web/H5关键词 + cookie/token/header
web版/抓包,B站签到,2025-01-11_bilibili_906ceaaa.js,906ceaaa11d344b7ecc1697e5f028c2999adb32569f3f9fca4feb951f86d3f46,GitHub,lksky8/sign-ql,invalid/bilibili.js,https://github.com/lksky8/sign-ql/blob/main/invalid/bilibili.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/bilibili.js,2025-01-11T18:49:38Z,脚本库/web版/抓包/B站签到/2025-01-11_bilibili_906ceaaa.js,抓包,web版,web/H5关键词 + cookie/token/header
web版/抓包,notify,2025-01-11_notify_9961f576.py,9961f57695cfba609fbfda0c314ab632f147c0d068b0f0338eaaa1ef796eedf8,GitHub,lksky8/sign-ql,notify.py,https://github.com/lksky8/sign-ql/blob/main/notify.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/notify.py,2025-01-11T18:39:35Z,脚本库/web版/抓包/notify/2025-01-11_notify_9961f576.py,抓包,web版,web/H5关键词 + cookie/token/header
web版/抓包,query,2026-05-11_ks_query_848504df.py,848504df99018b6b2f9d7bac940671dc65777b8d973c1610e2a3111c88d36480,GitHub,DearSong15/ql-scripts,ks_query.py,https://github.com/DearSong15/ql-scripts/blob/main/ks_query.py,https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_query.py,2026-05-11T14:51:55Z,脚本库/web版/抓包/query/2026-05-11_ks_query_848504df.py,抓包,web版,web/H5关键词 + cookie/token/header
web版/抓包,券妈妈时段奖励,2025-01-11_qmm_868f2cd3.js,868f2cd3002df5797fe7ad064612d6e5bc4b97d168092281a6390b7219643743,GitHub,lksky8/sign-ql,invalid/qmm.js,https://github.com/lksky8/sign-ql/blob/main/invalid/qmm.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/qmm.js,2025-01-11T18:42:58Z,脚本库/web版/抓包/券妈妈时段奖励/2025-01-11_qmm_868f2cd3.js,抓包,web版,web/H5关键词 + cookie/token/header
web版/账密,"'未知用户',",2026-05-19_juejin_checkin_6f8a138b.js,6f8a138b51c397220444c9312040dbe3407af5aeed4fa4467a36672aeb8bcfd1,GitHub,huwangkeji/juejin_checkin,juejin_checkin.js,https://github.com/huwangkeji/juejin_checkin/blob/main/juejin_checkin.js,https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin_checkin.js,2026-05-19T14:34:11Z,"脚本库/web版/账密/'未知用户',/2026-05-19_juejin_checkin_6f8a138b.js",账密,web版,web/H5关键词 + username/password/login
web版/账密,apply_link.split'id='-1},2026-03-27_3dmgame_2262c9f7.py,2262c9f7c2d40c8ef9822325fadd2e8ed3c43ba0f609c072a27c49b02edc2eaa,GitHub,lksky8/sign-ql,3dmgame.py,https://github.com/lksky8/sign-ql/blob/main/3dmgame.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/3dmgame.py,2026-03-27T20:17:30Z,脚本库/web版/账密/apply_link.split'id='-1}/2026-03-27_3dmgame_2262c9f7.py,账密,web版,web/H5关键词 + username/password/login
web版/账密,"str,_token_str",2025-09-22_PPark_120e7330.py,120e73308bc1ccfb9db8ebd87357364850257a25ba1bc039d67c2967fe6c8e19,GitHub,lksky8/sign-ql,PPark.py,https://github.com/lksky8/sign-ql/blob/main/PPark.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/PPark.py,2025-09-22T11:01:17Z,"脚本库/web版/账密/str,_token_str/2025-09-22_PPark_120e7330.py",账密,web版,web/H5关键词 + username/password/login
web版/账密,tyqh,2026-05-23_tyqh_4c779933.py,4c779933563a21d73534721d588cf8fd5aa9e6d6ced3e3b3bb414c91fb576708,GitHub,lksky8/sign-ql,invalid/tyqh.py,https://github.com/lksky8/sign-ql/blob/main/invalid/tyqh.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/tyqh.py,2026-05-23T06:33:20Z,脚本库/web版/账密/tyqh/2026-05-23_tyqh_4c779933.py,账密,web版,web/H5关键词 + username/password/login
web版/账密,"url.hostname,",2026-05-11_zsp_video_960b2e28.js,960b2e28799c40a00eb4bd75dcda1e61b3ab747374716073995c75053c3083ee,GitHub,DearSong15/ql-scripts,zsp_video.js,https://github.com/DearSong15/ql-scripts/blob/main/zsp_video.js,https://raw.githubusercontent.com/DearSong15/ql-scripts/main/zsp_video.js,2026-05-11T15:03:30Z,"脚本库/web版/账密/url.hostname,/2026-05-11_zsp_video_960b2e28.js",账密,web版,web/H5关键词 + username/password/login
web版/账密,yxw_appsign,2025-09-28_yxw_appsign_c6d91db1.py,c6d91db16e3a84bf5dfc1e2c7d6cb38fb3f6d38f5829d7f496ba308fa7a77a10,GitHub,lksky8/sign-ql,yxw_appsign.py,https://github.com/lksky8/sign-ql/blob/main/yxw_appsign.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_appsign.py,2025-09-28T06:42:50Z,脚本库/web版/账密/yxw_appsign/2025-09-28_yxw_appsign_c6d91db1.py,账密,web版,web/H5关键词 + username/password/login
web版/账密,yxw_luckbox,2025-08-21_yxw_luckbox_79511924.py,7951192443b96cec1fe801de769343a2e080be439b46c9b2bfb4372a4cdfe2e1,GitHub,lksky8/sign-ql,yxw_luckbox.py,https://github.com/lksky8/sign-ql/blob/main/yxw_luckbox.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_luckbox.py,2025-08-21T12:12:12Z,脚本库/web版/账密/yxw_luckbox/2025-08-21_yxw_luckbox_79511924.py,账密,web版,web/H5关键词 + username/password/login
web版/账密,中石化加油广东APP签到,2022-07-24_jygd_47493387.js,474933874ed61cd8ebd4efed3ee26778f4e3d0290ba16222f9feed61bafb6838,GitHub,lksky8/sign-ql,invalid/jygd.js,https://github.com/lksky8/sign-ql/blob/main/invalid/jygd.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/jygd.js,2022-07-24T02:54:25Z,脚本库/web版/账密/中石化加油广东APP签到/2022-07-24_jygd_47493387.js,账密,web版,web/H5关键词 + username/password/login
web版/账密,叮咚买菜,2022-11-17_ddmc_2d78fbea_2.js,2d78fbea0d710c7d29ad02178c603c97586bc9a5843ccd9f92cd18d6b8157c80,GitHub,lksky8/sign-ql,ddmc.js,https://github.com/lksky8/sign-ql/blob/main/ddmc.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/ddmc.js,2022-11-17T13:54:32Z,脚本库/web版/账密/叮咚买菜/2022-11-17_ddmc_2d78fbea_2.js,账密,web版,web/H5关键词 + username/password/login
web版/账密,方舟健客签到,2025-12-07_jksign_b722f903.py,b722f903ef41b1cab2540fc2a7b84bb51cb2e8d354783a225e3c364b0799a4e6,GitHub,lksky8/sign-ql,jksign.py,https://github.com/lksky8/sign-ql/blob/main/jksign.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/jksign.py,2025-12-07T17:42:50Z,脚本库/web版/账密/方舟健客签到/2025-12-07_jksign_b722f903.py,账密,web版,web/H5关键词 + username/password/login
web版/账密,星星充电签到,2025-09-01_xxcd_40e3aef4.py,40e3aef421127efd0fe80201c786cf341993dd4e8318fe4f8456a912aef026e0,GitHub,lksky8/sign-ql,xxcd.py,https://github.com/lksky8/sign-ql/blob/main/xxcd.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/xxcd.py,2025-09-01T15:45:21Z,脚本库/web版/账密/星星充电签到/2025-09-01_xxcd_40e3aef4.py,账密,web版,web/H5关键词 + username/password/login
微信小程序/抓包版,cloud189,2025-09-06_cloud189_7c90c2eb.py,7c90c2eb0032873254db7819a42440cd062ae32af3fa537efc7c295c0e1da804,GitHub,lksky8/sign-ql,cloud189.py,https://github.com/lksky8/sign-ql/blob/main/cloud189.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/cloud189.py,2025-09-06T12:51:46Z,脚本库/微信小程序/抓包版/cloud189/2025-09-06_cloud189_7c90c2eb.py,抓包版,微信小程序,appid/openid/session_key/encryptedData等小程序字段
微信小程序/抓包版,jtc,2025-10-26_jtc_d7fa5acd_2.py,d7fa5acdc107ddb45fd772c4bb0c9491fd48e8e3d7d18ae5a4286579151676ef,GitHub,lksky8/sign-ql,jtc.py,https://github.com/lksky8/sign-ql/blob/main/jtc.py,https://raw.githubusercontent.com/lksky8/sign-ql/main/jtc.py,2025-10-26T12:24:47Z,脚本库/微信小程序/抓包版/jtc/2025-10-26_jtc_d7fa5acd_2.py,抓包版,微信小程序,appid/openid/session_key/encryptedData等小程序字段
微信小程序/抓包版,快手双端,2026-05-11_ks_dual_aa4fbaa7.js,aa4fbaa74f4c00599fa2a8c1e358c99c6f393dc9b180b7c8260162ddd20b1e0f,GitHub,DearSong15/ql-scripts,ks_dual.js,https://github.com/DearSong15/ql-scripts/blob/main/ks_dual.js,https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_dual.js,2026-05-11T15:03:30Z,脚本库/微信小程序/抓包版/快手双端/2026-05-11_ks_dual_aa4fbaa7.js,抓包版,微信小程序,appid/openid/session_key/encryptedData等小程序字段
微信小程序/抓包版,滴滴果园,2025-01-11_ddgy_236924d1.js,236924d18d7e9ae58141a6c45bde1b9de748e6e63c8ca805162caf02fb01b362,GitHub,lksky8/sign-ql,invalid/ddgy.js,https://github.com/lksky8/sign-ql/blob/main/invalid/ddgy.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/ddgy.js,2025-01-11T18:50:13Z,脚本库/微信小程序/抓包版/滴滴果园/2025-01-11_ddgy_236924d1.js,抓包版,微信小程序,appid/openid/session_key/encryptedData等小程序字段
微信小程序/抓包版,索尼中国,2025-01-11_sonybbs_359e1e49.js,359e1e4984589cd0b5363e39c8ff9a566a54f3b5678cee3540b33ac3a546638a,GitHub,lksky8/sign-ql,invalid/sonybbs.js,https://github.com/lksky8/sign-ql/blob/main/invalid/sonybbs.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/sonybbs.js,2025-01-11T18:47:31Z,脚本库/微信小程序/抓包版/索尼中国/2025-01-11_sonybbs_359e1e49.js,抓包版,微信小程序,appid/openid/session_key/encryptedData等小程序字段
微信小程序/抓包版,统一茄皇-修复版,2023-01-03_tyqh_2fe80596.js,2fe8059609f086f32865e2d2463e2e54b532cae84923ca73cb64cf6d5432509c,GitHub,lksky8/sign-ql,invalid/tyqh.js,https://github.com/lksky8/sign-ql/blob/main/invalid/tyqh.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/tyqh.js,2023-01-03T11:39:58Z,脚本库/微信小程序/抓包版/统一茄皇-修复版/2023-01-03_tyqh_2fe80596.js,抓包版,微信小程序,appid/openid/session_key/encryptedData等小程序字段
微信小程序/抓包版,统一茄皇互助,2023-01-03_qhhz_07a8e366.js,07a8e366afc33d150d5b2c1d3dde5220e01ffa855b3c568244fe6013a54aae43,GitHub,lksky8/sign-ql,invalid/qhhz.js,https://github.com/lksky8/sign-ql/blob/main/invalid/qhhz.js,https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/qhhz.js,2023-01-03T11:38:28Z,脚本库/微信小程序/抓包版/统一茄皇互助/2023-01-03_qhhz_07a8e366.js,抓包版,微信小程序,appid/openid/session_key/encryptedData等小程序字段
1 category project filename sha256 source_platform source_repo source_path source_url raw_url uploaded_at saved_path auth_type platform_type evidence
2 APP版/抓包 content 2026-05-19_content_45c4e352.js 45c4e3523ff88ee080e76c2c8b635c4a14657f9f97fa395d368b9bccf09b4bca GitHub huwangkeji/juejin_checkin juejin-extension/content.js https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/content.js https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/content.js 2026-05-19T14:34:11Z 脚本库/APP版/抓包/content/2026-05-19_content_45c4e352.js 抓包 APP版 cookie/token/authorization/header
3 web版/抓包 'Cookie',_env_'JUEJIN_COOKIE',_isLong_true_}, 2026-05-19_popup_0a4d4983.js 0a4d49831a306fa984f62b0d1b3f26f7fc1274a625d08b5f4622ba94121b8469 GitHub huwangkeji/juejin_checkin juejin-extension/popup.js https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/popup.js https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/popup.js 2026-05-19T14:34:11Z 脚本库/web版/抓包/'Cookie',_env_'JUEJIN_COOKIE',_isLong_true_},/2026-05-19_popup_0a4d4983.js 抓包 web版 web/H5关键词 + cookie/token/header
4 web版/抓包 B站签到 2025-01-11_bilibili_906ceaaa.js 906ceaaa11d344b7ecc1697e5f028c2999adb32569f3f9fca4feb951f86d3f46 GitHub lksky8/sign-ql invalid/bilibili.js https://github.com/lksky8/sign-ql/blob/main/invalid/bilibili.js https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/bilibili.js 2025-01-11T18:49:38Z 脚本库/web版/抓包/B站签到/2025-01-11_bilibili_906ceaaa.js 抓包 web版 web/H5关键词 + cookie/token/header
5 web版/抓包 notify 2025-01-11_notify_9961f576.py 9961f57695cfba609fbfda0c314ab632f147c0d068b0f0338eaaa1ef796eedf8 GitHub lksky8/sign-ql notify.py https://github.com/lksky8/sign-ql/blob/main/notify.py https://raw.githubusercontent.com/lksky8/sign-ql/main/notify.py 2025-01-11T18:39:35Z 脚本库/web版/抓包/notify/2025-01-11_notify_9961f576.py 抓包 web版 web/H5关键词 + cookie/token/header
6 web版/抓包 query 2026-05-11_ks_query_848504df.py 848504df99018b6b2f9d7bac940671dc65777b8d973c1610e2a3111c88d36480 GitHub DearSong15/ql-scripts ks_query.py https://github.com/DearSong15/ql-scripts/blob/main/ks_query.py https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_query.py 2026-05-11T14:51:55Z 脚本库/web版/抓包/query/2026-05-11_ks_query_848504df.py 抓包 web版 web/H5关键词 + cookie/token/header
7 web版/抓包 券妈妈时段奖励 2025-01-11_qmm_868f2cd3.js 868f2cd3002df5797fe7ad064612d6e5bc4b97d168092281a6390b7219643743 GitHub lksky8/sign-ql invalid/qmm.js https://github.com/lksky8/sign-ql/blob/main/invalid/qmm.js https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/qmm.js 2025-01-11T18:42:58Z 脚本库/web版/抓包/券妈妈时段奖励/2025-01-11_qmm_868f2cd3.js 抓包 web版 web/H5关键词 + cookie/token/header
8 web版/账密 '未知用户', 2026-05-19_juejin_checkin_6f8a138b.js 6f8a138b51c397220444c9312040dbe3407af5aeed4fa4467a36672aeb8bcfd1 GitHub huwangkeji/juejin_checkin juejin_checkin.js https://github.com/huwangkeji/juejin_checkin/blob/main/juejin_checkin.js https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin_checkin.js 2026-05-19T14:34:11Z 脚本库/web版/账密/'未知用户',/2026-05-19_juejin_checkin_6f8a138b.js 账密 web版 web/H5关键词 + username/password/login
9 web版/账密 apply_link.split'id='-1} 2026-03-27_3dmgame_2262c9f7.py 2262c9f7c2d40c8ef9822325fadd2e8ed3c43ba0f609c072a27c49b02edc2eaa GitHub lksky8/sign-ql 3dmgame.py https://github.com/lksky8/sign-ql/blob/main/3dmgame.py https://raw.githubusercontent.com/lksky8/sign-ql/main/3dmgame.py 2026-03-27T20:17:30Z 脚本库/web版/账密/apply_link.split'id='-1}/2026-03-27_3dmgame_2262c9f7.py 账密 web版 web/H5关键词 + username/password/login
10 web版/账密 str,_token_str 2025-09-22_PPark_120e7330.py 120e73308bc1ccfb9db8ebd87357364850257a25ba1bc039d67c2967fe6c8e19 GitHub lksky8/sign-ql PPark.py https://github.com/lksky8/sign-ql/blob/main/PPark.py https://raw.githubusercontent.com/lksky8/sign-ql/main/PPark.py 2025-09-22T11:01:17Z 脚本库/web版/账密/str,_token_str/2025-09-22_PPark_120e7330.py 账密 web版 web/H5关键词 + username/password/login
11 web版/账密 tyqh 2026-05-23_tyqh_4c779933.py 4c779933563a21d73534721d588cf8fd5aa9e6d6ced3e3b3bb414c91fb576708 GitHub lksky8/sign-ql invalid/tyqh.py https://github.com/lksky8/sign-ql/blob/main/invalid/tyqh.py https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/tyqh.py 2026-05-23T06:33:20Z 脚本库/web版/账密/tyqh/2026-05-23_tyqh_4c779933.py 账密 web版 web/H5关键词 + username/password/login
12 web版/账密 url.hostname, 2026-05-11_zsp_video_960b2e28.js 960b2e28799c40a00eb4bd75dcda1e61b3ab747374716073995c75053c3083ee GitHub DearSong15/ql-scripts zsp_video.js https://github.com/DearSong15/ql-scripts/blob/main/zsp_video.js https://raw.githubusercontent.com/DearSong15/ql-scripts/main/zsp_video.js 2026-05-11T15:03:30Z 脚本库/web版/账密/url.hostname,/2026-05-11_zsp_video_960b2e28.js 账密 web版 web/H5关键词 + username/password/login
13 web版/账密 yxw_appsign 2025-09-28_yxw_appsign_c6d91db1.py c6d91db16e3a84bf5dfc1e2c7d6cb38fb3f6d38f5829d7f496ba308fa7a77a10 GitHub lksky8/sign-ql yxw_appsign.py https://github.com/lksky8/sign-ql/blob/main/yxw_appsign.py https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_appsign.py 2025-09-28T06:42:50Z 脚本库/web版/账密/yxw_appsign/2025-09-28_yxw_appsign_c6d91db1.py 账密 web版 web/H5关键词 + username/password/login
14 web版/账密 yxw_luckbox 2025-08-21_yxw_luckbox_79511924.py 7951192443b96cec1fe801de769343a2e080be439b46c9b2bfb4372a4cdfe2e1 GitHub lksky8/sign-ql yxw_luckbox.py https://github.com/lksky8/sign-ql/blob/main/yxw_luckbox.py https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_luckbox.py 2025-08-21T12:12:12Z 脚本库/web版/账密/yxw_luckbox/2025-08-21_yxw_luckbox_79511924.py 账密 web版 web/H5关键词 + username/password/login
15 web版/账密 中石化加油广东APP签到 2022-07-24_jygd_47493387.js 474933874ed61cd8ebd4efed3ee26778f4e3d0290ba16222f9feed61bafb6838 GitHub lksky8/sign-ql invalid/jygd.js https://github.com/lksky8/sign-ql/blob/main/invalid/jygd.js https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/jygd.js 2022-07-24T02:54:25Z 脚本库/web版/账密/中石化加油广东APP签到/2022-07-24_jygd_47493387.js 账密 web版 web/H5关键词 + username/password/login
16 web版/账密 叮咚买菜 2022-11-17_ddmc_2d78fbea_2.js 2d78fbea0d710c7d29ad02178c603c97586bc9a5843ccd9f92cd18d6b8157c80 GitHub lksky8/sign-ql ddmc.js https://github.com/lksky8/sign-ql/blob/main/ddmc.js https://raw.githubusercontent.com/lksky8/sign-ql/main/ddmc.js 2022-11-17T13:54:32Z 脚本库/web版/账密/叮咚买菜/2022-11-17_ddmc_2d78fbea_2.js 账密 web版 web/H5关键词 + username/password/login
17 web版/账密 方舟健客签到 2025-12-07_jksign_b722f903.py b722f903ef41b1cab2540fc2a7b84bb51cb2e8d354783a225e3c364b0799a4e6 GitHub lksky8/sign-ql jksign.py https://github.com/lksky8/sign-ql/blob/main/jksign.py https://raw.githubusercontent.com/lksky8/sign-ql/main/jksign.py 2025-12-07T17:42:50Z 脚本库/web版/账密/方舟健客签到/2025-12-07_jksign_b722f903.py 账密 web版 web/H5关键词 + username/password/login
18 web版/账密 星星充电签到 2025-09-01_xxcd_40e3aef4.py 40e3aef421127efd0fe80201c786cf341993dd4e8318fe4f8456a912aef026e0 GitHub lksky8/sign-ql xxcd.py https://github.com/lksky8/sign-ql/blob/main/xxcd.py https://raw.githubusercontent.com/lksky8/sign-ql/main/xxcd.py 2025-09-01T15:45:21Z 脚本库/web版/账密/星星充电签到/2025-09-01_xxcd_40e3aef4.py 账密 web版 web/H5关键词 + username/password/login
19 微信小程序/抓包版 cloud189 2025-09-06_cloud189_7c90c2eb.py 7c90c2eb0032873254db7819a42440cd062ae32af3fa537efc7c295c0e1da804 GitHub lksky8/sign-ql cloud189.py https://github.com/lksky8/sign-ql/blob/main/cloud189.py https://raw.githubusercontent.com/lksky8/sign-ql/main/cloud189.py 2025-09-06T12:51:46Z 脚本库/微信小程序/抓包版/cloud189/2025-09-06_cloud189_7c90c2eb.py 抓包版 微信小程序 appid/openid/session_key/encryptedData等小程序字段
20 微信小程序/抓包版 jtc 2025-10-26_jtc_d7fa5acd_2.py d7fa5acdc107ddb45fd772c4bb0c9491fd48e8e3d7d18ae5a4286579151676ef GitHub lksky8/sign-ql jtc.py https://github.com/lksky8/sign-ql/blob/main/jtc.py https://raw.githubusercontent.com/lksky8/sign-ql/main/jtc.py 2025-10-26T12:24:47Z 脚本库/微信小程序/抓包版/jtc/2025-10-26_jtc_d7fa5acd_2.py 抓包版 微信小程序 appid/openid/session_key/encryptedData等小程序字段
21 微信小程序/抓包版 快手双端 2026-05-11_ks_dual_aa4fbaa7.js aa4fbaa74f4c00599fa2a8c1e358c99c6f393dc9b180b7c8260162ddd20b1e0f GitHub DearSong15/ql-scripts ks_dual.js https://github.com/DearSong15/ql-scripts/blob/main/ks_dual.js https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_dual.js 2026-05-11T15:03:30Z 脚本库/微信小程序/抓包版/快手双端/2026-05-11_ks_dual_aa4fbaa7.js 抓包版 微信小程序 appid/openid/session_key/encryptedData等小程序字段
22 微信小程序/抓包版 滴滴果园 2025-01-11_ddgy_236924d1.js 236924d18d7e9ae58141a6c45bde1b9de748e6e63c8ca805162caf02fb01b362 GitHub lksky8/sign-ql invalid/ddgy.js https://github.com/lksky8/sign-ql/blob/main/invalid/ddgy.js https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/ddgy.js 2025-01-11T18:50:13Z 脚本库/微信小程序/抓包版/滴滴果园/2025-01-11_ddgy_236924d1.js 抓包版 微信小程序 appid/openid/session_key/encryptedData等小程序字段
23 微信小程序/抓包版 索尼中国 2025-01-11_sonybbs_359e1e49.js 359e1e4984589cd0b5363e39c8ff9a566a54f3b5678cee3540b33ac3a546638a GitHub lksky8/sign-ql invalid/sonybbs.js https://github.com/lksky8/sign-ql/blob/main/invalid/sonybbs.js https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/sonybbs.js 2025-01-11T18:47:31Z 脚本库/微信小程序/抓包版/索尼中国/2025-01-11_sonybbs_359e1e49.js 抓包版 微信小程序 appid/openid/session_key/encryptedData等小程序字段
24 微信小程序/抓包版 统一茄皇-修复版 2023-01-03_tyqh_2fe80596.js 2fe8059609f086f32865e2d2463e2e54b532cae84923ca73cb64cf6d5432509c GitHub lksky8/sign-ql invalid/tyqh.js https://github.com/lksky8/sign-ql/blob/main/invalid/tyqh.js https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/tyqh.js 2023-01-03T11:39:58Z 脚本库/微信小程序/抓包版/统一茄皇-修复版/2023-01-03_tyqh_2fe80596.js 抓包版 微信小程序 appid/openid/session_key/encryptedData等小程序字段
25 微信小程序/抓包版 统一茄皇互助 2023-01-03_qhhz_07a8e366.js 07a8e366afc33d150d5b2c1d3dde5220e01ffa855b3c568244fe6013a54aae43 GitHub lksky8/sign-ql invalid/qhhz.js https://github.com/lksky8/sign-ql/blob/main/invalid/qhhz.js https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/qhhz.js 2023-01-03T11:38:28Z 脚本库/微信小程序/抓包版/统一茄皇互助/2023-01-03_qhhz_07a8e366.js 抓包版 微信小程序 appid/openid/session_key/encryptedData等小程序字段

386
INDEX.json Normal file
View File

@@ -0,0 +1,386 @@
[
{
"category": "APP版/抓包",
"project": "content",
"filename": "2026-05-19_content_45c4e352.js",
"sha256": "45c4e3523ff88ee080e76c2c8b635c4a14657f9f97fa395d368b9bccf09b4bca",
"source_platform": "GitHub",
"source_repo": "huwangkeji/juejin_checkin",
"source_path": "juejin-extension/content.js",
"source_url": "https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/content.js",
"raw_url": "https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/content.js",
"uploaded_at": "2026-05-19T14:34:11Z",
"saved_path": "脚本库/APP版/抓包/content/2026-05-19_content_45c4e352.js",
"auth_type": "抓包",
"platform_type": "APP版",
"evidence": "cookie/token/authorization/header"
},
{
"category": "web版/抓包",
"project": "'Cookie',_env_'JUEJIN_COOKIE',_isLong_true_},",
"filename": "2026-05-19_popup_0a4d4983.js",
"sha256": "0a4d49831a306fa984f62b0d1b3f26f7fc1274a625d08b5f4622ba94121b8469",
"source_platform": "GitHub",
"source_repo": "huwangkeji/juejin_checkin",
"source_path": "juejin-extension/popup.js",
"source_url": "https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/popup.js",
"raw_url": "https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/popup.js",
"uploaded_at": "2026-05-19T14:34:11Z",
"saved_path": "脚本库/web版/抓包/'Cookie',_env_'JUEJIN_COOKIE',_isLong_true_},/2026-05-19_popup_0a4d4983.js",
"auth_type": "抓包",
"platform_type": "web版",
"evidence": "web/H5关键词 + cookie/token/header"
},
{
"category": "web版/抓包",
"project": "B站签到",
"filename": "2025-01-11_bilibili_906ceaaa.js",
"sha256": "906ceaaa11d344b7ecc1697e5f028c2999adb32569f3f9fca4feb951f86d3f46",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/bilibili.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/bilibili.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/bilibili.js",
"uploaded_at": "2025-01-11T18:49:38Z",
"saved_path": "脚本库/web版/抓包/B站签到/2025-01-11_bilibili_906ceaaa.js",
"auth_type": "抓包",
"platform_type": "web版",
"evidence": "web/H5关键词 + cookie/token/header"
},
{
"category": "web版/抓包",
"project": "notify",
"filename": "2025-01-11_notify_9961f576.py",
"sha256": "9961f57695cfba609fbfda0c314ab632f147c0d068b0f0338eaaa1ef796eedf8",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "notify.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/notify.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/notify.py",
"uploaded_at": "2025-01-11T18:39:35Z",
"saved_path": "脚本库/web版/抓包/notify/2025-01-11_notify_9961f576.py",
"auth_type": "抓包",
"platform_type": "web版",
"evidence": "web/H5关键词 + cookie/token/header"
},
{
"category": "web版/抓包",
"project": "query",
"filename": "2026-05-11_ks_query_848504df.py",
"sha256": "848504df99018b6b2f9d7bac940671dc65777b8d973c1610e2a3111c88d36480",
"source_platform": "GitHub",
"source_repo": "DearSong15/ql-scripts",
"source_path": "ks_query.py",
"source_url": "https://github.com/DearSong15/ql-scripts/blob/main/ks_query.py",
"raw_url": "https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_query.py",
"uploaded_at": "2026-05-11T14:51:55Z",
"saved_path": "脚本库/web版/抓包/query/2026-05-11_ks_query_848504df.py",
"auth_type": "抓包",
"platform_type": "web版",
"evidence": "web/H5关键词 + cookie/token/header"
},
{
"category": "web版/抓包",
"project": "券妈妈时段奖励",
"filename": "2025-01-11_qmm_868f2cd3.js",
"sha256": "868f2cd3002df5797fe7ad064612d6e5bc4b97d168092281a6390b7219643743",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/qmm.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/qmm.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/qmm.js",
"uploaded_at": "2025-01-11T18:42:58Z",
"saved_path": "脚本库/web版/抓包/券妈妈时段奖励/2025-01-11_qmm_868f2cd3.js",
"auth_type": "抓包",
"platform_type": "web版",
"evidence": "web/H5关键词 + cookie/token/header"
},
{
"category": "web版/账密",
"project": "'未知用户',",
"filename": "2026-05-19_juejin_checkin_6f8a138b.js",
"sha256": "6f8a138b51c397220444c9312040dbe3407af5aeed4fa4467a36672aeb8bcfd1",
"source_platform": "GitHub",
"source_repo": "huwangkeji/juejin_checkin",
"source_path": "juejin_checkin.js",
"source_url": "https://github.com/huwangkeji/juejin_checkin/blob/main/juejin_checkin.js",
"raw_url": "https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin_checkin.js",
"uploaded_at": "2026-05-19T14:34:11Z",
"saved_path": "脚本库/web版/账密/'未知用户',/2026-05-19_juejin_checkin_6f8a138b.js",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "apply_link.split'id='-1}",
"filename": "2026-03-27_3dmgame_2262c9f7.py",
"sha256": "2262c9f7c2d40c8ef9822325fadd2e8ed3c43ba0f609c072a27c49b02edc2eaa",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "3dmgame.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/3dmgame.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/3dmgame.py",
"uploaded_at": "2026-03-27T20:17:30Z",
"saved_path": "脚本库/web版/账密/apply_link.split'id='-1}/2026-03-27_3dmgame_2262c9f7.py",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "str,_token_str",
"filename": "2025-09-22_PPark_120e7330.py",
"sha256": "120e73308bc1ccfb9db8ebd87357364850257a25ba1bc039d67c2967fe6c8e19",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "PPark.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/PPark.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/PPark.py",
"uploaded_at": "2025-09-22T11:01:17Z",
"saved_path": "脚本库/web版/账密/str,_token_str/2025-09-22_PPark_120e7330.py",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "tyqh",
"filename": "2026-05-23_tyqh_4c779933.py",
"sha256": "4c779933563a21d73534721d588cf8fd5aa9e6d6ced3e3b3bb414c91fb576708",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/tyqh.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/tyqh.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/tyqh.py",
"uploaded_at": "2026-05-23T06:33:20Z",
"saved_path": "脚本库/web版/账密/tyqh/2026-05-23_tyqh_4c779933.py",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "url.hostname,",
"filename": "2026-05-11_zsp_video_960b2e28.js",
"sha256": "960b2e28799c40a00eb4bd75dcda1e61b3ab747374716073995c75053c3083ee",
"source_platform": "GitHub",
"source_repo": "DearSong15/ql-scripts",
"source_path": "zsp_video.js",
"source_url": "https://github.com/DearSong15/ql-scripts/blob/main/zsp_video.js",
"raw_url": "https://raw.githubusercontent.com/DearSong15/ql-scripts/main/zsp_video.js",
"uploaded_at": "2026-05-11T15:03:30Z",
"saved_path": "脚本库/web版/账密/url.hostname,/2026-05-11_zsp_video_960b2e28.js",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "yxw_appsign",
"filename": "2025-09-28_yxw_appsign_c6d91db1.py",
"sha256": "c6d91db16e3a84bf5dfc1e2c7d6cb38fb3f6d38f5829d7f496ba308fa7a77a10",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "yxw_appsign.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/yxw_appsign.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_appsign.py",
"uploaded_at": "2025-09-28T06:42:50Z",
"saved_path": "脚本库/web版/账密/yxw_appsign/2025-09-28_yxw_appsign_c6d91db1.py",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "yxw_luckbox",
"filename": "2025-08-21_yxw_luckbox_79511924.py",
"sha256": "7951192443b96cec1fe801de769343a2e080be439b46c9b2bfb4372a4cdfe2e1",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "yxw_luckbox.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/yxw_luckbox.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_luckbox.py",
"uploaded_at": "2025-08-21T12:12:12Z",
"saved_path": "脚本库/web版/账密/yxw_luckbox/2025-08-21_yxw_luckbox_79511924.py",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "中石化加油广东APP签到",
"filename": "2022-07-24_jygd_47493387.js",
"sha256": "474933874ed61cd8ebd4efed3ee26778f4e3d0290ba16222f9feed61bafb6838",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/jygd.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/jygd.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/jygd.js",
"uploaded_at": "2022-07-24T02:54:25Z",
"saved_path": "脚本库/web版/账密/中石化加油广东APP签到/2022-07-24_jygd_47493387.js",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "叮咚买菜",
"filename": "2022-11-17_ddmc_2d78fbea_2.js",
"sha256": "2d78fbea0d710c7d29ad02178c603c97586bc9a5843ccd9f92cd18d6b8157c80",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "ddmc.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/ddmc.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/ddmc.js",
"uploaded_at": "2022-11-17T13:54:32Z",
"saved_path": "脚本库/web版/账密/叮咚买菜/2022-11-17_ddmc_2d78fbea_2.js",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "方舟健客签到",
"filename": "2025-12-07_jksign_b722f903.py",
"sha256": "b722f903ef41b1cab2540fc2a7b84bb51cb2e8d354783a225e3c364b0799a4e6",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "jksign.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/jksign.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/jksign.py",
"uploaded_at": "2025-12-07T17:42:50Z",
"saved_path": "脚本库/web版/账密/方舟健客签到/2025-12-07_jksign_b722f903.py",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "web版/账密",
"project": "星星充电签到",
"filename": "2025-09-01_xxcd_40e3aef4.py",
"sha256": "40e3aef421127efd0fe80201c786cf341993dd4e8318fe4f8456a912aef026e0",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "xxcd.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/xxcd.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/xxcd.py",
"uploaded_at": "2025-09-01T15:45:21Z",
"saved_path": "脚本库/web版/账密/星星充电签到/2025-09-01_xxcd_40e3aef4.py",
"auth_type": "账密",
"platform_type": "web版",
"evidence": "web/H5关键词 + username/password/login"
},
{
"category": "微信小程序/抓包版",
"project": "cloud189",
"filename": "2025-09-06_cloud189_7c90c2eb.py",
"sha256": "7c90c2eb0032873254db7819a42440cd062ae32af3fa537efc7c295c0e1da804",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "cloud189.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/cloud189.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/cloud189.py",
"uploaded_at": "2025-09-06T12:51:46Z",
"saved_path": "脚本库/微信小程序/抓包版/cloud189/2025-09-06_cloud189_7c90c2eb.py",
"auth_type": "抓包版",
"platform_type": "微信小程序",
"evidence": "appid/openid/session_key/encryptedData等小程序字段"
},
{
"category": "微信小程序/抓包版",
"project": "jtc",
"filename": "2025-10-26_jtc_d7fa5acd_2.py",
"sha256": "d7fa5acdc107ddb45fd772c4bb0c9491fd48e8e3d7d18ae5a4286579151676ef",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "jtc.py",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/jtc.py",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/jtc.py",
"uploaded_at": "2025-10-26T12:24:47Z",
"saved_path": "脚本库/微信小程序/抓包版/jtc/2025-10-26_jtc_d7fa5acd_2.py",
"auth_type": "抓包版",
"platform_type": "微信小程序",
"evidence": "appid/openid/session_key/encryptedData等小程序字段"
},
{
"category": "微信小程序/抓包版",
"project": "快手双端",
"filename": "2026-05-11_ks_dual_aa4fbaa7.js",
"sha256": "aa4fbaa74f4c00599fa2a8c1e358c99c6f393dc9b180b7c8260162ddd20b1e0f",
"source_platform": "GitHub",
"source_repo": "DearSong15/ql-scripts",
"source_path": "ks_dual.js",
"source_url": "https://github.com/DearSong15/ql-scripts/blob/main/ks_dual.js",
"raw_url": "https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_dual.js",
"uploaded_at": "2026-05-11T15:03:30Z",
"saved_path": "脚本库/微信小程序/抓包版/快手双端/2026-05-11_ks_dual_aa4fbaa7.js",
"auth_type": "抓包版",
"platform_type": "微信小程序",
"evidence": "appid/openid/session_key/encryptedData等小程序字段"
},
{
"category": "微信小程序/抓包版",
"project": "滴滴果园",
"filename": "2025-01-11_ddgy_236924d1.js",
"sha256": "236924d18d7e9ae58141a6c45bde1b9de748e6e63c8ca805162caf02fb01b362",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/ddgy.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/ddgy.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/ddgy.js",
"uploaded_at": "2025-01-11T18:50:13Z",
"saved_path": "脚本库/微信小程序/抓包版/滴滴果园/2025-01-11_ddgy_236924d1.js",
"auth_type": "抓包版",
"platform_type": "微信小程序",
"evidence": "appid/openid/session_key/encryptedData等小程序字段"
},
{
"category": "微信小程序/抓包版",
"project": "索尼中国",
"filename": "2025-01-11_sonybbs_359e1e49.js",
"sha256": "359e1e4984589cd0b5363e39c8ff9a566a54f3b5678cee3540b33ac3a546638a",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/sonybbs.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/sonybbs.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/sonybbs.js",
"uploaded_at": "2025-01-11T18:47:31Z",
"saved_path": "脚本库/微信小程序/抓包版/索尼中国/2025-01-11_sonybbs_359e1e49.js",
"auth_type": "抓包版",
"platform_type": "微信小程序",
"evidence": "appid/openid/session_key/encryptedData等小程序字段"
},
{
"category": "微信小程序/抓包版",
"project": "统一茄皇-修复版",
"filename": "2023-01-03_tyqh_2fe80596.js",
"sha256": "2fe8059609f086f32865e2d2463e2e54b532cae84923ca73cb64cf6d5432509c",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/tyqh.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/tyqh.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/tyqh.js",
"uploaded_at": "2023-01-03T11:39:58Z",
"saved_path": "脚本库/微信小程序/抓包版/统一茄皇-修复版/2023-01-03_tyqh_2fe80596.js",
"auth_type": "抓包版",
"platform_type": "微信小程序",
"evidence": "appid/openid/session_key/encryptedData等小程序字段"
},
{
"category": "微信小程序/抓包版",
"project": "统一茄皇互助",
"filename": "2023-01-03_qhhz_07a8e366.js",
"sha256": "07a8e366afc33d150d5b2c1d3dde5220e01ffa855b3c568244fe6013a54aae43",
"source_platform": "GitHub",
"source_repo": "lksky8/sign-ql",
"source_path": "invalid/qhhz.js",
"source_url": "https://github.com/lksky8/sign-ql/blob/main/invalid/qhhz.js",
"raw_url": "https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/qhhz.js",
"uploaded_at": "2023-01-03T11:38:28Z",
"saved_path": "脚本库/微信小程序/抓包版/统一茄皇互助/2023-01-03_qhhz_07a8e366.js",
"auth_type": "抓包版",
"platform_type": "微信小程序",
"evidence": "appid/openid/session_key/encryptedData等小程序字段"
}
]

47
README.md Normal file
View File

@@ -0,0 +1,47 @@
# 青龙脚本分类库
本仓库用于归档公开青龙脚本,并按运行端与凭证方式分类。
## 分类
- `APP版/抓包`1 个脚本1 个项目
- `APP版/账密`0 个脚本0 个项目
- `web版/抓包`5 个脚本5 个项目
- `web版/账密`11 个脚本11 个项目
- `微信小程序/协议版`0 个脚本0 个项目
- `微信小程序/抓包版`7 个脚本7 个项目
- `未分类`0 个脚本0 个项目
## 目录规则
```text
脚本库/APP版/抓包/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext
脚本库/APP版/账密/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext
脚本库/web版/抓包/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext
脚本库/web版/账密/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext
脚本库/微信小程序/协议版/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext
脚本库/微信小程序/抓包版/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext
```
## 元数据
- `INDEX.csv`:脚本索引,含分类、项目、源仓库、源路径、源 URL、上传时间、SHA256。
- `INDEX.json`同上JSON 格式。
- 文件名中的日期优先使用源文件最近一次 commit 时间。
- 相同代码以归一化 SHA256 去重。
## 采集器
运行:
```bash
python3 collector.py
```
可选环境变量:
```bash
export GITHUB_TOKEN=你的GitHubToken # 可提升 GitHub API 限额
export MAX_REPOS_PER_QUERY=20
export MAX_FILES_TOTAL=500
```

764
collector.py Normal file
View File

@@ -0,0 +1,764 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
公开青龙脚本采集器(多来源首轮版)
目标:
- 从公开代码平台/公开网页入口搜索青龙/QL 脚本;
- 按 APP版/抓包、APP版/账密、web版/抓包、web版/账密、微信小程序/协议版、微信小程序/抓包版分类;
- 以代码内容 SHA256 去重;
- 同项目不同代码放入同一项目目录;
- 记录源仓库、源路径、源 URL、上传/提交时间。
说明:
- GitHub 搜索 API 未配置 token 时有限流;可设置 GITHUB_TOKEN 提升额度。
- “上传时间”优先取该文件最近一次 commit 的 commit.committer.date失败时退化为仓库 pushed_at。
"""
from __future__ import annotations
import base64
import csv
import hashlib
import json
import os
import re
import time
import unicodedata
import urllib.parse
from dataclasses import dataclass, asdict
from pathlib import Path
from typing import Dict, Iterable, List, Optional, Tuple
try:
import requests
except ModuleNotFoundError: # 便于在新环境直接运行
import subprocess
import sys as _sys
subprocess.check_call([_sys.executable, "-m", "pip", "install", "requests", "-q", "--break-system-packages"])
import requests
ROOT = Path(__file__).resolve().parent
OUT_DIR = ROOT / "脚本库"
META_DIR = ROOT / "metadata"
INDEX_CSV = ROOT / "INDEX.csv"
INDEX_JSON = ROOT / "INDEX.json"
README = ROOT / "README.md"
CACHE = META_DIR / "collector_cache.json"
MAX_REPOS_PER_QUERY = int(os.getenv("MAX_REPOS_PER_QUERY", "12"))
MAX_FILES_TOTAL = int(os.getenv("MAX_FILES_TOTAL", "260"))
REQUEST_SLEEP = float(os.getenv("REQUEST_SLEEP", "0.4"))
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN", "").strip()
SESSION = requests.Session()
SESSION.headers.update({
"User-Agent": "ql-script-classifier/1.0",
"Accept": "application/vnd.github+json",
})
if GITHUB_TOKEN:
SESSION.headers["Authorization"] = f"Bearer {GITHUB_TOKEN}"
SEARCH_QUERIES = [
# 青龙/QL 常用关键词
"青龙 脚本 language:JavaScript",
"青龙 脚本 language:Python",
"qinglong script language:JavaScript",
"qinglong script language:Python",
"ql repo script language:JavaScript",
'"new Env" "cron" language:JavaScript',
'"new Env" "青龙" language:JavaScript',
'"ql repo" "new Env" language:JavaScript',
'"青龙面板" "new Env" language:JavaScript',
'"微信小程序" "青龙" language:Python',
'"wx_token" "wx_cloud" language:Python',
'"getMiniProgramCode" language:Python',
'"getMiniProgramCode" language:JavaScript',
]
GITEE_SEARCH_QUERIES = [
"青龙 脚本",
"new Env 青龙",
"wx_token wx_cloud",
"getMiniProgramCode",
]
# 其它公开网页入口:只处理公开可访问的代码页/raw 链接;不处理需要登录、私密分享或绕权的网盘。
WEB_SEARCH_QUERIES = [
'青龙 脚本 "new Env"',
'青龙脚本 "ql repo"',
'青龙脚本 "wx_token" "wx_cloud"',
'青龙脚本 "getMiniProgramCode"',
'青龙脚本 site:gitee.com',
'青龙脚本 site:gitcode.com',
'青龙脚本 site:agit.ai',
'青龙脚本 site:raw.githubusercontent.com',
]
VALID_SUFFIXES = {".js", ".py", ".ts", ".sh"}
SKIP_PATH_KEYWORDS = {
"node_modules", ".git", "dist/", "build/", "package-lock", "yarn.lock",
"readme", "license", "docker", "workflow", ".github", "icon", "image", "png", "jpg",
}
CATEGORY_ORDER = [
"APP版/抓包",
"APP版/账密",
"web版/抓包",
"web版/账密",
"微信小程序/协议版",
"微信小程序/抓包版",
"未分类",
]
@dataclass
class Record:
category: str
project: str
filename: str
sha256: str
source_platform: str
source_repo: str
source_path: str
source_url: str
raw_url: str
uploaded_at: str
saved_path: str
auth_type: str
platform_type: str
evidence: str
def safe_segment(text: str, fallback: str = "unknown", max_len: int = 80) -> str:
text = unicodedata.normalize("NFKC", text or "")
text = re.sub(r"[\\/:*?\"<>|\s]+", "_", text).strip("._-")
text = re.sub(r"_+", "_", text)
if not text:
text = fallback
return text[:max_len]
def normalized_hash(content: str) -> str:
# 去 BOM、统一换行、去末尾空白不删除注释避免误合并不同版本
norm = content.replace("\r\n", "\n").replace("\r", "\n").lstrip("\ufeff")
norm = "\n".join(line.rstrip() for line in norm.split("\n")).strip() + "\n"
return hashlib.sha256(norm.encode("utf-8", "ignore")).hexdigest()
def github_get(url: str, **kwargs):
time.sleep(REQUEST_SLEEP)
r = SESSION.get(url, timeout=30, **kwargs)
if r.status_code == 403 and "rate limit" in r.text.lower():
reset = r.headers.get("X-RateLimit-Reset")
print(f"[WARN] GitHub rate limited: {url} reset={reset}")
raise RuntimeError("github_rate_limited")
if r.status_code >= 400:
print(f"[WARN] HTTP {r.status_code}: {url} {r.text[:160]}")
return None
return r
def search_github_repos() -> List[dict]:
repos: Dict[str, dict] = {}
for q in SEARCH_QUERIES:
url = "https://api.github.com/search/repositories"
params = {"q": q, "sort": "updated", "order": "desc", "per_page": MAX_REPOS_PER_QUERY}
print(f"[SEARCH] {q}", flush=True)
r = github_get(url, params=params)
if not r:
continue
data = r.json()
for item in data.get("items", []):
full = item.get("full_name")
if full and full not in repos:
repos[full] = item
return list(repos.values())
def generic_get(url: str, **kwargs):
time.sleep(REQUEST_SLEEP)
headers = kwargs.pop("headers", {}) or {}
merged = {"User-Agent": "Mozilla/5.0 ql-script-classifier/1.0", **headers}
try:
r = SESSION.get(url, timeout=30, headers=merged, **kwargs)
if r.status_code >= 400:
print(f"[WARN] HTTP {r.status_code}: {url} {r.text[:120]}")
return None
return r
except Exception as e:
print(f"[WARN] GET failed: {url} {e}")
return None
def search_gitee_repos() -> List[dict]:
"""Gitee 公开搜索。API 搜索经常返回空,因此同时解析公开搜索页。"""
repos: Dict[str, dict] = {}
for q in GITEE_SEARCH_QUERIES:
print(f"[GITEE_SEARCH] {q}")
# API 尝试
api = "https://gitee.com/api/v5/search/repositories"
r = generic_get(api, params={"q": q, "page": 1, "per_page": MAX_REPOS_PER_QUERY})
if r:
try:
data = r.json()
if isinstance(data, list):
for item in data:
full = item.get("full_name") or item.get("path_with_namespace")
if full:
repos[full] = item
except Exception:
pass
# HTML 搜索页尝试
html_url = "https://gitee.com/search"
# HTML 搜索容易被前端页面拖慢/反爬,默认仅使用 API如需扩展可后续加入定向种子仓库。
return list(repos.values())
def list_gitee_tree(repo: dict) -> List[dict]:
full = repo.get("full_name") or repo.get("path_with_namespace")
if not full:
return []
branch = repo.get("default_branch") or "master"
for b in [branch, "master", "main"]:
api = f"https://gitee.com/api/v5/repos/{urllib.parse.quote(str(full), safe='')}/git/trees/{urllib.parse.quote(str(b))}"
r = generic_get(api, params={"recursive": 1})
if not r:
continue
try:
data = r.json()
tree = data.get("tree") if isinstance(data, dict) else None
if isinstance(tree, list):
repo["default_branch"] = b
return tree
except Exception:
continue
return []
def get_gitee_file_content(repo_full: str, path: str, branch: str) -> Tuple[Optional[str], str, str]:
# raw URL 不需要 token 的公开仓库通常可直接访问
raw_url = f"https://gitee.com/{repo_full}/raw/{urllib.parse.quote(branch)}/{urllib.parse.quote(path)}"
html_url = f"https://gitee.com/{repo_full}/blob/{urllib.parse.quote(branch)}/{urllib.parse.quote(path)}"
r = generic_get(raw_url)
if r and len(r.content) <= 1024 * 1024:
return r.content.decode("utf-8", "ignore"), raw_url, html_url
return None, raw_url, html_url
def get_gitee_file_uploaded_at(repo_full: str, path: str, fallback: str) -> str:
# Gitee commit API 兼容性不稳定;失败时退化到 repo pushed_at 或空。
encoded_repo = urllib.parse.quote(repo_full, safe="")
api = f"https://gitee.com/api/v5/repos/{encoded_repo}/commits"
r = generic_get(api, params={"path": path, "page": 1, "per_page": 1})
if r:
try:
data = r.json()
if isinstance(data, list) and data:
c = data[0]
return ((c.get("commit") or {}).get("committer") or {}).get("date") or c.get("created_at") or fallback or ""
except Exception:
pass
return fallback or ""
def discover_public_code_links() -> List[dict]:
"""通过公开搜索页发现 raw/js/py 链接。使用 DuckDuckGo HTML无登录。"""
links: Dict[str, dict] = {}
if os.getenv("ENABLE_WEB_SEARCH", "false").strip().lower() != "true":
print("[WEB_SEARCH] disabled; set ENABLE_WEB_SEARCH=true to enable public web search")
return []
for q in WEB_SEARCH_QUERIES:
print(f"[WEB_SEARCH] {q}")
url = "https://duckduckgo.com/html/"
r = generic_get(url, params={"q": q})
if not r:
continue
html = r.text
for m in re.finditer(r'href="([^"]+)"', html):
href = m.group(1)
href = href.replace("&amp;", "&")
if "uddg=" in href:
qs = urllib.parse.parse_qs(urllib.parse.urlparse(href).query)
href = qs.get("uddg", [href])[0]
if not re.search(r"\.(js|py|ts|sh)(\?|$)", href, flags=re.I):
continue
if not any(host in href for host in ["githubusercontent.com", "gitee.com", "gitcode", "agit.ai", "raw"]):
continue
links[href] = {"url": href}
return list(links.values())
def get_public_link_content(url: str) -> Tuple[Optional[str], str, str, str]:
raw_url = url
html_url = url
# GitHub blob -> raw
m = re.match(r"https://github\.com/([^/]+/[^/]+)/blob/([^/]+)/(.+)", url)
if m:
raw_url = f"https://raw.githubusercontent.com/{m.group(1)}/{m.group(2)}/{m.group(3)}"
# Gitee blob -> raw
m = re.match(r"https://gitee\.com/([^/]+/[^/]+)/blob/([^/]+)/(.+)", url)
if m:
raw_url = f"https://gitee.com/{m.group(1)}/raw/{m.group(2)}/{m.group(3)}"
r = generic_get(raw_url)
if r and len(r.content) <= 1024 * 1024:
return r.content.decode("utf-8", "ignore"), raw_url, html_url, ""
return None, raw_url, html_url, ""
def list_github_tree(repo: dict) -> List[dict]:
full = repo["full_name"]
branch = repo.get("default_branch") or "main"
url = f"https://api.github.com/repos/{full}/git/trees/{urllib.parse.quote(branch)}?recursive=1"
r = github_get(url)
if not r:
return []
data = r.json()
return data.get("tree", [])
def is_candidate_path(path: str) -> bool:
lower = path.lower()
if any(k in lower for k in SKIP_PATH_KEYWORDS):
return False
if Path(path).suffix.lower() not in VALID_SUFFIXES:
return False
# 常见脚本路径或文件内容关键词由后续判断;这里不过窄过滤
return True
def get_file_content(repo_full: str, path: str, branch: str) -> Tuple[Optional[str], str, str]:
encoded = urllib.parse.quote(path, safe="")
url = f"https://api.github.com/repos/{repo_full}/contents/{encoded}?ref={urllib.parse.quote(branch)}"
r = github_get(url)
if not r:
return None, "", ""
data = r.json()
raw_url = data.get("download_url", "")
html_url = data.get("html_url", "")
content = data.get("content")
if data.get("encoding") == "base64" and content:
try:
b = base64.b64decode(content)
if len(b) > 1024 * 1024:
return None, raw_url, html_url
text = b.decode("utf-8", "ignore")
return text, raw_url, html_url
except Exception:
return None, raw_url, html_url
if raw_url:
rr = github_get(raw_url)
if rr:
return rr.text, raw_url, html_url
return None, raw_url, html_url
def get_file_uploaded_at(repo_full: str, path: str, fallback: str) -> str:
encoded = urllib.parse.quote(path, safe="")
url = f"https://api.github.com/repos/{repo_full}/commits?path={encoded}&per_page=1"
r = github_get(url)
if not r:
return fallback or ""
arr = r.json()
if isinstance(arr, list) and arr:
commit = arr[0].get("commit", {})
return (commit.get("committer") or {}).get("date") or (commit.get("author") or {}).get("date") or fallback or ""
return fallback or ""
def looks_like_ql_script(content: str, path: str) -> bool:
lower = content.lower()
score = 0
keywords = [
"new env", "cron:", "ql repo", "青龙", "notify", "sendnotify", "process.env",
"requests.", "axios", "got(", "wx_token", "jd_cookie", "cookie", "authorization",
"getminiprogramcode", "wx_cloud", "wx.login", "小程序",
]
for k in keywords:
if k in lower:
score += 1
if Path(path).suffix.lower() in {".js", ".py", ".sh"}:
score += 1
return score >= 2
def extract_project(content: str, path: str) -> str:
patterns = [
r"new\s+Env\([\"']([^\"']{2,80})[\"']\)",
r"new\s+Env\s*\([`\"]([^`\"]{2,80})[`\"]\)",
r"#\s*new\s+Env\([\"']([^\"']{2,80})[\"']\)",
r"项目[:]\s*([^\n\r]{2,60})",
r"name[:]\s*([^\n\r]{2,60})",
]
for pat in patterns:
m = re.search(pat, content, flags=re.I)
if m:
name = m.group(1).strip()
name = re.sub(r"[【】\[\]()]", "", name).strip()
if name:
return safe_segment(name)
stem = Path(path).stem
stem = re.sub(r"^(ql_|jd_|jx_|ks_|wx_|applet_)", "", stem, flags=re.I)
return safe_segment(stem)
def classify(content: str, path: str) -> Tuple[str, str, str, str]:
text = content
lower = text.lower()
evidence = []
is_wx_protocol = any(k in lower for k in [
"getminiprogramcode", "wx_cloud", "wx_token", "miniprogramcode", "养鸡场", "wx.login", "code2session"
])
is_wx = is_wx_protocol or any(k in lower for k in [
"appid", "openid", "session_key", "encrypteddata", "小程序", "wechat/login", "wxappid"
])
has_pwd = any(k in lower for k in [
"password", "passwd", "pwd", "username", "user_name", "account", "账密", "手机号登录", "mobile", "smscode", "验证码"
]) and any(k in lower for k in ["login", "登录", "/auth", "/user/login"])
has_capture = any(k in lower for k in [
"cookie", "authorization", "bearer", "token", "x-token", "session", "抓包", "header", "headers", "ck"
])
web_hint = any(k in lower for k in [
"web", "h5", "pc", "browser", "chrome", "网页登录", "www.", "passport", "csrf"
])
app_hint = any(k in lower for k in [
"app", "android", "ios", "okhttp", "x-requested-with", "user-agent", "deviceid", "imei", "oaid"
])
if is_wx_protocol:
evidence.append("getMiniProgramCode/wx_cloud/wx_token/code协议链路")
return "微信小程序/协议版", "微信小程序", "协议版", "; ".join(evidence)
if is_wx:
evidence.append("appid/openid/session_key/encryptedData等小程序字段")
return "微信小程序/抓包版", "微信小程序", "抓包版", "; ".join(evidence)
if web_hint and has_pwd:
evidence.append("web/H5关键词 + username/password/login")
return "web版/账密", "web版", "账密", "; ".join(evidence)
if web_hint and has_capture:
evidence.append("web/H5关键词 + cookie/token/header")
return "web版/抓包", "web版", "抓包", "; ".join(evidence)
if has_pwd:
evidence.append("username/password/mobile/login")
return "APP版/账密", "APP版", "账密", "; ".join(evidence)
if has_capture:
evidence.append("cookie/token/authorization/header")
return "APP版/抓包", "APP版", "抓包", "; ".join(evidence)
if app_hint:
evidence.append("APP/Android/iOS/device关键词")
return "APP版/抓包", "APP版", "抓包", "; ".join(evidence)
return "未分类", "未分类", "未分类", "规则未命中"
def unique_filename(project_dir: Path, uploaded_at: str, original: str, sha: str) -> str:
date = (uploaded_at or "unknown")[:10] or "unknown"
stem = safe_segment(Path(original).stem, "script", 60)
suffix = Path(original).suffix or ".txt"
name = f"{date}_{stem}_{sha[:8]}{suffix}"
i = 2
while (project_dir / name).exists():
name = f"{date}_{stem}_{sha[:8]}_{i}{suffix}"
i += 1
return name
def write_record_file(record: Record, content: str):
out_path = ROOT / record.saved_path
out_path.parent.mkdir(parents=True, exist_ok=True)
header = (
f"# Source: {record.source_url}\n"
f"# Raw: {record.raw_url}\n"
f"# Repo: {record.source_repo}\n"
f"# Path: {record.source_path}\n"
f"# UploadedAt: {record.uploaded_at}\n"
f"# SHA256: {record.sha256}\n"
f"# Category: {record.category}\n"
f"# Evidence: {record.evidence}\n\n"
)
if out_path.suffix.lower() == ".py":
header = header
elif out_path.suffix.lower() in {".js", ".ts"}:
header = "// " + header.replace("\n", "\n// ").rstrip("// ") + "\n"
elif out_path.suffix.lower() == ".sh":
header = header
out_path.write_text(header + content, encoding="utf-8", errors="ignore")
def load_seen_hashes() -> set:
if INDEX_JSON.exists():
try:
arr = json.loads(INDEX_JSON.read_text(encoding="utf-8"))
return {x.get("sha256") for x in arr if x.get("sha256")}
except Exception:
return set()
return set()
def save_indexes(records: List[Record]):
existing = []
if INDEX_JSON.exists():
try:
existing = json.loads(INDEX_JSON.read_text(encoding="utf-8"))
except Exception:
existing = []
by_sha = {x.get("sha256"): x for x in existing if x.get("sha256")}
for r in records:
by_sha[r.sha256] = asdict(r)
arr = sorted(by_sha.values(), key=lambda x: (x.get("category", ""), x.get("project", ""), x.get("uploaded_at", "")))
INDEX_JSON.write_text(json.dumps(arr, ensure_ascii=False, indent=2), encoding="utf-8")
with INDEX_CSV.open("w", newline="", encoding="utf-8-sig") as f:
fields = list(asdict(records[0]).keys()) if records else [
"category", "project", "filename", "sha256", "source_platform", "source_repo", "source_path",
"source_url", "raw_url", "uploaded_at", "saved_path", "auth_type", "platform_type", "evidence"
]
w = csv.DictWriter(f, fieldnames=fields)
w.writeheader()
for item in arr:
w.writerow(item)
def update_readme():
arr = []
if INDEX_JSON.exists():
arr = json.loads(INDEX_JSON.read_text(encoding="utf-8"))
counts = {c: 0 for c in CATEGORY_ORDER}
projects = {}
for x in arr:
counts[x.get("category", "未分类")] = counts.get(x.get("category", "未分类"), 0) + 1
projects.setdefault(x.get("category", "未分类"), set()).add(x.get("project", "unknown"))
lines = [
"# 青龙脚本分类库\n",
"\n",
"本仓库用于归档公开青龙脚本,并按运行端与凭证方式分类。\n",
"\n",
"## 分类\n",
"\n",
]
for c in CATEGORY_ORDER:
lines.append(f"- `{c}`{counts.get(c,0)} 个脚本,{len(projects.get(c,set()))} 个项目\n")
lines += [
"\n",
"## 目录规则\n",
"\n",
"```text\n",
"脚本库/APP版/抓包/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext\n",
"脚本库/APP版/账密/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext\n",
"脚本库/web版/抓包/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext\n",
"脚本库/web版/账密/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext\n",
"脚本库/微信小程序/协议版/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext\n",
"脚本库/微信小程序/抓包版/<项目>/YYYY-MM-DD_原文件名_<sha8>.ext\n",
"```\n",
"\n",
"## 元数据\n",
"\n",
"- `INDEX.csv`:脚本索引,含分类、项目、源仓库、源路径、源 URL、上传时间、SHA256。\n",
"- `INDEX.json`同上JSON 格式。\n",
"- 文件名中的日期优先使用源文件最近一次 commit 时间。\n",
"- 相同代码以归一化 SHA256 去重。\n",
"\n",
"## 采集器\n",
"\n",
"运行:\n",
"\n",
"```bash\n",
"python3 collector.py\n",
"```\n",
"\n",
"可选环境变量:\n",
"\n",
"```bash\n",
"export GITHUB_TOKEN=你的GitHubToken # 可提升 GitHub API 限额\n",
"export MAX_REPOS_PER_QUERY=20\n",
"export MAX_FILES_TOTAL=500\n",
"```\n",
]
README.write_text("".join(lines), encoding="utf-8")
def add_content_record(
records: List[Record],
seen: set,
content: str,
source_platform: str,
source_repo: str,
source_path: str,
source_url: str,
raw_url: str,
uploaded_at: str,
) -> bool:
if not content or not looks_like_ql_script(content, source_path):
return False
sha = normalized_hash(content)
if sha in seen:
return False
category, platform_type, auth_type, evidence = classify(content, source_path)
project = extract_project(content, source_path)
project_dir = OUT_DIR / category / project
fname = unique_filename(project_dir, uploaded_at, Path(source_path).name, sha)
saved_path = str((project_dir / fname).relative_to(ROOT))
rec = Record(
category=category,
project=project,
filename=fname,
sha256=sha,
source_platform=source_platform,
source_repo=source_repo,
source_path=source_path,
source_url=source_url,
raw_url=raw_url,
uploaded_at=uploaded_at,
saved_path=saved_path,
auth_type=auth_type,
platform_type=platform_type,
evidence=evidence,
)
write_record_file(rec, content)
records.append(rec)
seen.add(sha)
print(f" [ADD] {category} / {project} / {fname}")
return True
def collect_github(records: List[Record], seen: set, files_done: int) -> int:
repos = search_github_repos()
print(f"[INFO] github_repos={len(repos)}")
for repo in repos:
if files_done >= MAX_FILES_TOTAL:
break
full = repo.get("full_name")
if not full:
continue
full = str(full)
branch = str(repo.get("default_branch") or "main")
print(f"[GITHUB_REPO] {full}")
tree = list_github_tree(repo)
candidates = [x for x in tree if x.get("type") == "blob" and is_candidate_path(x.get("path", ""))]
candidates.sort(key=lambda x: (
0 if re.search(r"(?i)(script|scripts|ql|青龙|jd_|wx_|applet|env)", x.get("path", "")) else 1,
len(x.get("path", ""))
))
for item in candidates[:80]:
if files_done >= MAX_FILES_TOTAL:
break
path = item.get("path", "")
content, raw_url, html_url = get_file_content(full, path, branch)
uploaded_at = get_file_uploaded_at(full, path, repo.get("pushed_at", "")) if content else ""
if add_content_record(records, seen, content or "", "GitHub", full, path, html_url, raw_url, uploaded_at):
files_done += 1
return files_done
def collect_gitee(records: List[Record], seen: set, files_done: int) -> int:
repos = search_gitee_repos()
print(f"[INFO] gitee_repos={len(repos)}")
for repo in repos:
if files_done >= MAX_FILES_TOTAL:
break
full = repo.get("full_name") or repo.get("path_with_namespace")
if not full:
continue
full = str(full)
branch = str(repo.get("default_branch") or "master")
print(f"[GITEE_REPO] {full}")
tree = list_gitee_tree(repo)
branch = str(repo.get("default_branch") or branch)
candidates = [x for x in tree if x.get("type") in ("blob", "file") and is_candidate_path(x.get("path", ""))]
candidates.sort(key=lambda x: (
0 if re.search(r"(?i)(script|scripts|ql|青龙|jd_|wx_|applet|env)", x.get("path", "")) else 1,
len(x.get("path", ""))
))
for item in candidates[:80]:
if files_done >= MAX_FILES_TOTAL:
break
path = item.get("path", "")
content, raw_url, html_url = get_gitee_file_content(full, path, branch)
uploaded_at = get_gitee_file_uploaded_at(full, path, repo.get("pushed_at", "")) if content else ""
if add_content_record(records, seen, content or "", "Gitee", full, path, html_url, raw_url, uploaded_at):
files_done += 1
return files_done
def collect_public_links(records: List[Record], seen: set, files_done: int) -> int:
links = discover_public_code_links()
print(f"[INFO] public_links={len(links)}")
for item in links:
if files_done >= MAX_FILES_TOTAL:
break
url = item.get("url", "")
content, raw_url, html_url, uploaded_at = get_public_link_content(url)
source_repo = urllib.parse.urlparse(url).netloc
source_path = urllib.parse.urlparse(url).path.strip("/") or Path(url).name
if add_content_record(records, seen, content or "", "PublicWeb", source_repo, source_path, html_url, raw_url, uploaded_at):
files_done += 1
return files_done
def rebuild_index_from_files():
"""当采集被限流/中断后,可从已落盘脚本头部重建 INDEX。"""
records = []
for path in OUT_DIR.rglob("*"):
if not path.is_file() or path.suffix.lower() not in VALID_SUFFIXES:
continue
text = path.read_text(encoding="utf-8", errors="ignore")
head = "\n".join(text.splitlines()[:12])
def pick(name):
m = re.search(rf"{name}:\s*(.+)", head)
return m.group(1).strip().lstrip("// ").strip() if m else ""
rel = str(path.relative_to(ROOT))
parts = path.relative_to(OUT_DIR).parts
if len(parts) < 4:
continue
category = f"{parts[0]}/{parts[1]}" if parts[0] in {"APP版", "web版", "微信小程序"} else parts[0]
project = parts[2] if len(parts) >= 4 else "unknown"
rec = Record(
category=category,
project=project,
filename=path.name,
sha256=pick("SHA256") or normalized_hash(text),
source_platform="GitHub",
source_repo=pick("Repo"),
source_path=pick("Path"),
source_url=pick("Source"),
raw_url=pick("Raw"),
uploaded_at=pick("UploadedAt"),
saved_path=rel,
auth_type=category.split("/")[-1] if "/" in category else "未分类",
platform_type=category.split("/")[0] if "/" in category else "未分类",
evidence=pick("Evidence"),
)
records.append(rec)
save_indexes(records)
update_readme()
print(f"[REBUILD] records={len(records)}")
def main():
OUT_DIR.mkdir(parents=True, exist_ok=True)
META_DIR.mkdir(parents=True, exist_ok=True)
seen = load_seen_hashes()
records: List[Record] = []
files_done = 0
try:
files_done = collect_github(records, seen, files_done)
except RuntimeError as e:
if str(e) == "github_rate_limited":
print("[WARN] GitHub 限流,跳过 GitHub 剩余采集,继续其它来源")
else:
raise
if files_done < MAX_FILES_TOTAL:
files_done = collect_gitee(records, seen, files_done)
if files_done < MAX_FILES_TOTAL:
files_done = collect_public_links(records, seen, files_done)
if records:
save_indexes(records)
update_readme()
elif any(OUT_DIR.rglob("*")):
rebuild_index_from_files()
else:
save_indexes(records)
update_readme()
print(f"[DONE] added={len(records)} total_files_done={files_done}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,176 @@
// # Source: https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/content.js
// # Raw: https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/content.js
// # Repo: huwangkeji/juejin_checkin
// # Path: juejin-extension/content.js
// # UploadedAt: 2026-05-19T14:34:11Z
// # SHA256: 45c4e3523ff88ee080e76c2c8b635c4a14657f9f97fa395d368b9bccf09b4bca
// # Category: APP版/抓包
// # Evidence: cookie/token/authorization/header
//
/**
* 掘金参数提取器 - Content Script (MAIN world)
* 直接在页面主世界运行hook 真实的 fetch/XHR参数存到 sessionStorage
*/
(function() {
'use strict';
if (window.__JUEJIN_EXTRACTOR_HOOKED__) return;
window.__JUEJIN_EXTRACTOR_HOOKED__ = true;
const STORAGE_KEY = '__juejin_extractor_data__';
function readStored() {
try {
return JSON.parse(sessionStorage.getItem(STORAGE_KEY) || '{}');
} catch (e) {
return {};
}
}
function writeStored(data) {
const existing = readStored();
const merged = { ...existing, ...data };
try {
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(merged));
} catch (e) {}
}
function extractFromUrl(url) {
try {
const u = new URL(url);
if (u.hostname === 'api.juejin.cn' || u.hostname.includes('juejin.cn')) {
return {
aid: u.searchParams.get('aid') || '',
uuid: u.searchParams.get('uuid') || '',
msToken: u.searchParams.get('msToken') || '',
a_bogus: u.searchParams.get('a_bogus') || '',
spider: u.searchParams.get('spider') || '',
};
}
} catch (e) {}
return null;
}
function mergeParams(params, cookie) {
const data = readStored();
let changed = false;
if (cookie && cookie.length > 10) {
data.cookie = cookie;
changed = true;
}
if (params.aid && params.aid !== 'null' && params.aid !== data.aid) {
data.aid = params.aid;
changed = true;
}
if (params.uuid && params.uuid.length > 5 && params.uuid !== data.uuid) {
data.uuid = params.uuid;
changed = true;
}
if (params.msToken && params.msToken.length > 5 && params.msToken !== data.msToken) {
data.msToken = params.msToken;
changed = true;
}
if (params.a_bogus && params.a_bogus.length > 5 && params.a_bogus !== data.a_bogus) {
data.a_bogus = params.a_bogus;
changed = true;
}
if (params.spider && params.spider !== data.spider) {
data.spider = params.spider;
changed = true;
}
if (changed) {
data.captureTime = new Date().toLocaleString('zh-CN');
writeStored(data);
}
}
// ===== Hook fetch =====
const _origFetch = window.fetch;
window.fetch = function fetchHook(input, init) {
try {
const url = typeof input === 'string' ? input : (input.url || input.toString());
const params = extractFromUrl(url);
if (params) {
let cookie = '';
try { cookie = document.cookie; } catch (e) {}
mergeParams(params, cookie);
}
} catch (e) {}
return _origFetch.apply(this, arguments);
};
// ===== Hook XMLHttpRequest =====
const _origOpen = XMLHttpRequest.prototype.open;
const _origSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url) {
this._juejinUrl = url;
return _origOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(body) {
try {
if (this._juejinUrl) {
const params = extractFromUrl(this._juejinUrl);
if (params) {
let cookie = '';
try { cookie = document.cookie; } catch (e) {}
mergeParams(params, cookie);
}
}
} catch (e) {}
return _origSend.apply(this, arguments);
};
// ===== 扫描 performance entries =====
function scanPerf() {
try {
const entries = performance.getEntriesByType('resource');
for (const entry of entries) {
if (entry.name && entry.name.includes('api.juejin.cn')) {
const params = extractFromUrl(entry.name);
if (params) {
let cookie = '';
try { cookie = document.cookie; } catch (e) {}
mergeParams(params, cookie);
}
}
}
} catch (e) {}
}
scanPerf();
let count = 0;
const timer = setInterval(() => {
scanPerf();
count++;
if (count >= 20) clearInterval(timer);
}, 2000);
// ===== 页面稳定后主动触发 harmless 请求 =====
function triggerCapture() {
try {
const t = Date.now();
_origFetch.call(window,
`https://api.juejin.cn/growth_api/v1/get_today_status?aid=2608&t=${t}`,
{ credentials: 'include', headers: { 'Accept': 'application/json' } }
).catch(() => {});
} catch (e) {}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(triggerCapture, 1000);
setTimeout(triggerCapture, 3000);
});
} else {
setTimeout(triggerCapture, 1000);
setTimeout(triggerCapture, 3000);
}
console.log('[掘金参数提取器] Content script (MAIN world) 已注入');
})();

View File

@@ -0,0 +1,292 @@
// # Source: https://github.com/huwangkeji/juejin_checkin/blob/main/juejin-extension/popup.js
// # Raw: https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin-extension/popup.js
// # Repo: huwangkeji/juejin_checkin
// # Path: juejin-extension/popup.js
// # UploadedAt: 2026-05-19T14:34:11Z
// # SHA256: 0a4d49831a306fa984f62b0d1b3f26f7fc1274a625d08b5f4622ba94121b8469
// # Category: web版/抓包
// # Evidence: web/H5关键词 + cookie/token/header
//
/**
* 掘金参数提取器 - Popup脚本
*/
// 参数配置key、显示名、青龙环境变量名
const PARAM_CONFIG = [
{ key: 'cookie', name: 'Cookie', env: 'JUEJIN_COOKIE', isLong: true },
{ key: 'aid', name: 'AID', env: 'JUEJIN_AID', isLong: false },
{ key: 'uuid', name: 'UUID', env: 'JUEJIN_UUID', isLong: true },
{ key: 'msToken', name: 'msToken', env: 'JUEJIN_MSTOKEN', isLong: true },
{ key: 'a_bogus', name: 'a_bogus', env: 'JUEJIN_A_BOGUS', isLong: true },
];
let currentData = null;
// 加载数据
async function loadData() {
return new Promise((resolve) => {
chrome.storage.local.get('juejinData', (result) => {
resolve(result.juejinData || null);
});
});
}
// 渲染界面
async function render() {
currentData = await loadData();
const emptyState = document.getElementById('emptyState');
const paramsList = document.getElementById('paramsList');
const actionsBar = document.getElementById('actionsBar');
const statusDot = document.getElementById('statusDot');
const statusText = document.getElementById('statusText');
const captureTime = document.getElementById('captureTime');
if (!currentData || !currentData.cookie) {
// 无数据
emptyState.style.display = 'block';
paramsList.style.display = 'none';
actionsBar.style.display = 'none';
statusDot.className = 'status-dot empty';
statusText.textContent = '等待捕获...';
captureTime.textContent = '';
return;
}
// 有数据
emptyState.style.display = 'none';
paramsList.style.display = 'block';
actionsBar.style.display = 'flex';
statusDot.className = 'status-dot captured';
statusText.textContent = '✅ 参数已捕获';
captureTime.textContent = currentData.captureTime || '';
// 渲染参数列表
paramsList.innerHTML = PARAM_CONFIG.map((config) => {
const value = currentData[config.key] || '';
const isEmpty = !value;
const displayValue = isEmpty ? '未捕获到' : value;
const valueClass = isEmpty ? 'param-value empty' : 'param-value';
return `
<div class="param-item">
<div class="param-header">
<span class="param-name">${config.name}</span>
<div style="display:flex;align-items:center;gap:6px;">
<span class="param-env">${config.env}</span>
<button class="copy-btn" data-key="${config.key}" title="复制${config.name}">复制</button>
</div>
</div>
<div class="${valueClass}" title="${displayValue}">${displayValue}</div>
</div>
`;
}).join('');
// 绑定复制按钮
paramsList.querySelectorAll('.copy-btn').forEach((btn) => {
btn.addEventListener('click', () => {
const key = btn.dataset.key;
const value = currentData[key] || '';
copyToClipboard(value, btn);
});
});
}
// 复制到剪贴板
function copyToClipboard(text, btn) {
navigator.clipboard.writeText(text).then(() => {
if (btn) {
const original = btn.textContent;
btn.textContent = '已复制 ✓';
btn.classList.add('copied');
setTimeout(() => {
btn.textContent = original;
btn.classList.remove('copied');
}, 1500);
}
});
}
// 生成青龙面板环境变量格式
function generateQinglongFormat() {
if (!currentData) return '';
const lines = [];
lines.push('# 掘金签到脚本 - 青龙面板环境变量');
lines.push('# 复制以下内容到青龙面板 -> 环境变量');
lines.push('');
lines.push(`JUEJIN_COOKIE='${currentData.cookie || ''}'`);
lines.push(`JUEJIN_AID='${currentData.aid || '2608'}'`);
lines.push(`JUEJIN_UUID='${currentData.uuid || ''}'`);
lines.push(`JUEJIN_MSTOKEN='${currentData.msToken || ''}'`);
lines.push(`JUEJIN_A_BOGUS='${currentData.a_bogus || ''}'`);
lines.push('');
lines.push(`# 捕获时间: ${currentData.captureTime || '未知'}`);
lines.push('# 参数有效期约30天过期需重新获取');
return lines.join('\n');
}
// 绑定事件
document.getElementById('copyAllBtn').addEventListener('click', () => {
const text = generateQinglongFormat();
copyToClipboard(text, document.getElementById('copyAllBtn'));
});
document.getElementById('goJuejinBtn').addEventListener('click', () => {
chrome.tabs.create({ url: 'https://juejin.cn' });
});
document.getElementById('refreshBtn').addEventListener('click', () => {
render();
});
// "从当前页面提取"按钮
document.getElementById('extractNowBtn').addEventListener('click', async () => {
const btn = document.getElementById('extractNowBtn');
const originalText = btn.textContent;
btn.textContent = '⏳ 提取中...';
btn.disabled = true;
try {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab || !tab.url || !tab.url.includes('juejin.cn')) {
alert('请先在掘金网站 (juejin.cn) 页面点击此按钮');
btn.textContent = originalText;
btn.disabled = false;
return;
}
// 在页面中执行提取脚本:主动发请求 -> 等待 hook 捕获 -> 读取 sessionStorage
const results = await chrome.scripting.executeScript({
target: { tabId: tab.id, allFrames: false },
world: 'MAIN',
func: () => {
return new Promise((resolve) => {
const data = {
cookie: '',
aid: '',
uuid: '',
msToken: '',
a_bogus: '',
spider: '',
captureTime: new Date().toLocaleString('zh-CN'),
captureUrl: location.href,
};
// 辅助:从 URL 提取参数
function extractFromUrl(url) {
try {
const u = new URL(url);
return {
aid: u.searchParams.get('aid') || '',
uuid: u.searchParams.get('uuid') || '',
msToken: u.searchParams.get('msToken') || '',
a_bogus: u.searchParams.get('a_bogus') || '',
spider: u.searchParams.get('spider') || '',
};
} catch (e) { return null; }
}
// 1. 获取 cookie
try { data.cookie = document.cookie; } catch (e) {}
// 2. 扫描 performance entries
try {
const entries = performance.getEntriesByType('resource');
for (const entry of entries) {
if (entry.name && entry.name.includes('api.juejin.cn')) {
const p = extractFromUrl(entry.name);
if (p) {
if (p.aid) data.aid = p.aid;
if (p.uuid && p.uuid.length > 5) data.uuid = p.uuid;
if (p.msToken && p.msToken.length > 5) data.msToken = p.msToken;
if (p.a_bogus && p.a_bogus.length > 5) data.a_bogus = p.a_bogus;
if (p.spider) data.spider = p.spider;
}
}
}
} catch (e) {}
// 3. 从 content script 的 sessionStorage 读取(如果 content.js 已捕获)
try {
const stored = JSON.parse(sessionStorage.getItem('__juejin_extractor_data__') || '{}');
if (stored.cookie) data.cookie = stored.cookie;
if (stored.aid) data.aid = stored.aid;
if (stored.uuid) data.uuid = stored.uuid;
if (stored.msToken) data.msToken = stored.msToken;
if (stored.a_bogus) data.a_bogus = stored.a_bogus;
if (stored.spider) data.spider = stored.spider;
} catch (e) {}
// 4. 主动触发一个请求来诱捕参数content.js 的 MAIN world hook 会捕获)
const needsTrigger = !data.uuid || !data.msToken || !data.a_bogus;
if (needsTrigger) {
try {
fetch('https://api.juejin.cn/growth_api/v1/get_today_status?aid=2608', {
credentials: 'include',
headers: { 'Accept': 'application/json' },
}).catch(() => {});
fetch('https://api.juejin.cn/user_api/v1/user/get?aid=2608', {
credentials: 'include',
headers: { 'Accept': 'application/json' },
}).catch(() => {});
} catch (e) {}
// 等待 hook 处理后再读取
setTimeout(() => {
try {
const stored2 = JSON.parse(sessionStorage.getItem('__juejin_extractor_data__') || '{}');
if (stored2.cookie) data.cookie = stored2.cookie;
if (stored2.aid) data.aid = stored2.aid;
if (stored2.uuid) data.uuid = stored2.uuid;
if (stored2.msToken) data.msToken = stored2.msToken;
if (stored2.a_bogus) data.a_bogus = stored2.a_bogus;
if (stored2.spider) data.spider = stored2.spider;
} catch (e) {}
resolve(data);
}, 800);
} else {
resolve(data);
}
});
},
});
const extracted = results[0]?.result;
if (extracted) {
// 合并到已有数据
chrome.storage.local.get('juejinData', (result) => {
const existing = result.juejinData || {};
const merged = {
...existing,
...Object.fromEntries(
Object.entries(extracted).filter(([_, v]) => v && v !== '')
),
};
chrome.storage.local.set({ juejinData: merged }, () => {
render();
btn.textContent = '✅ 提取完成';
setTimeout(() => {
btn.textContent = originalText;
btn.disabled = false;
}, 1500);
});
});
} else {
alert('未能从当前页面提取到参数,请刷新页面后重试');
btn.textContent = originalText;
btn.disabled = false;
}
} catch (e) {
console.error(e);
alert('提取失败: ' + e.message);
btn.textContent = originalText;
btn.disabled = false;
}
});
// 初始渲染
render();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,574 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/notify.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/notify.py
# Repo: lksky8/sign-ql
# Path: notify.py
# UploadedAt: 2025-01-11T18:39:35Z
# SHA256: 9961f57695cfba609fbfda0c314ab632f147c0d068b0f0338eaaa1ef796eedf8
# Category: web版/抓包
# Evidence: web/H5关键词 + cookie/token/header
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import base64
import hashlib
import hmac
import json
import os
import re
import threading
import time
import urllib.parse
import requests
# 原先的 print 函数和主线程的锁
_print = print
mutex = threading.Lock()
# 定义新的 print 函数
def print(text, *args, **kw):
"""
使输出有序进行,不出现多线程同一时间输出导致错乱的问题。
"""
with mutex:
_print(text, *args, **kw)
# 通知服务
# fmt: off
push_config = {
'HITOKOTO': False, # 启用一言(随机句子)
'BARK_PUSH': '', # bark IP 或设备码https://api.day.app/DxHcxxxxxRxxxxxxcm/
'BARK_ARCHIVE': '', # bark 推送是否存档
'BARK_GROUP': '', # bark 推送分组
'BARK_SOUND': '', # bark 推送声音
'BARK_ICON': '', # bark 推送图标
'CONSOLE': True, # 控制台输出
'DD_BOT_SECRET': '', # 钉钉机器人的 DD_BOT_SECRET
'DD_BOT_TOKEN': '', # 钉钉机器人的 DD_BOT_TOKEN
'FSKEY': '', # 飞书机器人的 FSKEY
'GOBOT_URL': '', # go-cqhttp
# 推送到个人QQhttp://127.0.0.1/send_private_msg
# 群http://127.0.0.1/send_group_msg
'GOBOT_QQ': '', # go-cqhttp 的推送群或用户
# GOBOT_URL 设置 /send_private_msg 时填入 user_id=个人QQ
# /send_group_msg 时填入 group_id=QQ群
'GOBOT_TOKEN': '', # go-cqhttp 的 access_token
'GOTIFY_URL': '', # gotify地址,如https://push.example.de:8080
'GOTIFY_TOKEN': '', # gotify的消息应用token
'GOTIFY_PRIORITY': 0, # 推送消息优先级,默认为0
'IGOT_PUSH_KEY': '', # iGot 聚合推送的 IGOT_PUSH_KEY
'PUSH_KEY': '', # server 酱的 PUSH_KEY兼容旧版与 Turbo 版
'DEER_KEY': '', # PushDeer 的 PUSHDEER_KEY
'PUSH_PLUS_TOKEN': '', # push+ 微信推送的用户令牌
'PUSH_PLUS_USER': '', # push+ 微信推送的群组编码
'QMSG_KEY': '', # qmsg 酱的 QMSG_KEY
'QMSG_TYPE': '', # qmsg 酱的 QMSG_TYPE
'QYWX_AM': '', # 企业微信应用
'QYWX_KEY': '', # 企业微信机器人
'TG_BOT_TOKEN': '', # tg 机器人的 TG_BOT_TOKEN1407203283:AAG9rt-6RDaaX0HBLZQq0laNOh898iFYaRQ
'TG_USER_ID': '', # tg 机器人的 TG_USER_ID1434078534
'TG_API_HOST': '', # tg 代理 api
'TG_PROXY_AUTH': '', # tg 代理认证参数
'TG_PROXY_HOST': '', # tg 机器人的 TG_PROXY_HOST
'TG_PROXY_PORT': '', # tg 机器人的 TG_PROXY_PORT
}
notify_function = []
# fmt: on
# 首先读取 面板变量 或者 github action 运行变量
for k in push_config:
if os.getenv(k):
v = os.getenv(k)
push_config[k] = v
def bark(title: str, content: str) -> None:
"""
使用 bark 推送消息。
"""
if not push_config.get("BARK_PUSH"):
print("bark 服务的 BARK_PUSH 未设置!!\n取消推送")
return
print("bark 服务启动")
if push_config.get("BARK_PUSH").startswith("http"):
url = f'{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
else:
url = f'https://api.day.app/{push_config.get("BARK_PUSH")}/{urllib.parse.quote_plus(title)}/{urllib.parse.quote_plus(content)}'
bark_params = {
"BARK_ARCHIVE": "isArchive",
"BARK_GROUP": "group",
"BARK_SOUND": "sound",
"BARK_ICON": "icon",
}
params = ""
for pair in filter(
lambda pairs: pairs[0].startswith("BARK_")
and pairs[0] != "BARK_PUSH"
and pairs[1]
and bark_params.get(pairs[0]),
push_config.items(),
):
params += f"{bark_params.get(pair[0])}={pair[1]}&"
if params:
url = url + "?" + params.rstrip("&")
response = requests.get(url).json()
if response["code"] == 200:
print("bark 推送成功!")
else:
print("bark 推送失败!")
def console(title: str, content: str) -> None:
"""
使用 控制台 推送消息。
"""
print(f"{title}\n\n{content}")
def dingding_bot(title: str, content: str) -> None:
"""
使用 钉钉机器人 推送消息。
"""
if not push_config.get("DD_BOT_SECRET") or not push_config.get("DD_BOT_TOKEN"):
print("钉钉机器人 服务的 DD_BOT_SECRET 或者 DD_BOT_TOKEN 未设置!!\n取消推送")
return
print("钉钉机器人 服务启动")
timestamp = str(round(time.time() * 1000))
secret_enc = push_config.get("DD_BOT_SECRET").encode("utf-8")
string_to_sign = "{}\n{}".format(timestamp, push_config.get("DD_BOT_SECRET"))
string_to_sign_enc = string_to_sign.encode("utf-8")
hmac_code = hmac.new(
secret_enc, string_to_sign_enc, digestmod=hashlib.sha256
).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
url = f'https://oapi.dingtalk.com/robot/send?access_token={push_config.get("DD_BOT_TOKEN")}&timestamp={timestamp}&sign={sign}'
headers = {"Content-Type": "application/json;charset=utf-8"}
data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
response = requests.post(
url=url, data=json.dumps(data), headers=headers, timeout=15
).json()
if not response["errcode"]:
print("钉钉机器人 推送成功!")
else:
print("钉钉机器人 推送失败!")
def feishu_bot(title: str, content: str) -> None:
"""
使用 飞书机器人 推送消息。
"""
if not push_config.get("FSKEY"):
print("飞书 服务的 FSKEY 未设置!!\n取消推送")
return
print("飞书 服务启动")
url = f'https://open.feishu.cn/open-apis/bot/v2/hook/{push_config.get("FSKEY")}'
data = {"msg_type": "text", "content": {"text": f"{title}\n\n{content}"}}
response = requests.post(url, data=json.dumps(data)).json()
if response.get("StatusCode") == 0:
print("飞书 推送成功!")
else:
print("飞书 推送失败!错误信息如下:\n", response)
def go_cqhttp(title: str, content: str) -> None:
"""
使用 go_cqhttp 推送消息。
"""
if not push_config.get("GOBOT_URL") or not push_config.get("GOBOT_QQ"):
print("go-cqhttp 服务的 GOBOT_URL 或 GOBOT_QQ 未设置!!\n取消推送")
return
print("go-cqhttp 服务启动")
url = f'{push_config.get("GOBOT_URL")}?access_token={push_config.get("GOBOT_TOKEN")}&{push_config.get("GOBOT_QQ")}&message=标题:{title}\n内容:{content}'
response = requests.get(url).json()
if response["status"] == "ok":
print("go-cqhttp 推送成功!")
else:
print("go-cqhttp 推送失败!")
def gotify(title:str,content:str) -> None:
"""
使用 gotify 推送消息。
"""
if not push_config.get("GOTIFY_URL") or not push_config.get("GOTIFY_TOKEN"):
print("gotify 服务的 GOTIFY_URL 或 GOTIFY_TOKEN 未设置!!\n取消推送")
return
print("gotify 服务启动")
url = f'{push_config.get("GOTIFY_URL")}/message?token={push_config.get("GOTIFY_TOKEN")}'
data = {"title": title,"message": content,"priority": push_config.get("GOTIFY_PRIORITY")}
response = requests.post(url,data=data).json()
if response.get("id"):
print("gotify 推送成功!")
else:
print("gotify 推送失败!")
def iGot(title: str, content: str) -> None:
"""
使用 iGot 推送消息。
"""
if not push_config.get("IGOT_PUSH_KEY"):
print("iGot 服务的 IGOT_PUSH_KEY 未设置!!\n取消推送")
return
print("iGot 服务启动")
url = f'https://push.hellyw.com/{push_config.get("IGOT_PUSH_KEY")}'
data = {"title": title, "content": content}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=data, headers=headers).json()
if response["ret"] == 0:
print("iGot 推送成功!")
else:
print(f'iGot 推送失败!{response["errMsg"]}')
def serverJ(title: str, content: str) -> None:
"""
通过 serverJ 推送消息。
"""
if not push_config.get("PUSH_KEY"):
print("serverJ 服务的 PUSH_KEY 未设置!!\n取消推送")
return
print("serverJ 服务启动")
data = {"text": title, "desp": content.replace("\n", "\n\n")}
if push_config.get("PUSH_KEY").index("SCT") != -1:
url = f'https://sctapi.ftqq.com/{push_config.get("PUSH_KEY")}.send'
else:
url = f'https://sc.ftqq.com/${push_config.get("PUSH_KEY")}.send'
response = requests.post(url, data=data).json()
if response.get("errno") == 0 or response.get("code") == 0:
print("serverJ 推送成功!")
else:
print(f'serverJ 推送失败!错误码:{response["message"]}')
def pushdeer(title: str, content: str) -> None:
"""
通过PushDeer 推送消息
"""
if not push_config.get("DEER_KEY"):
print("PushDeer 服务的 DEER_KEY 未设置!!\n取消推送")
return
print("PushDeer 服务启动")
data = {"text": title, "desp": content, "type": "markdown", "pushkey": push_config.get("DEER_KEY")}
url = 'https://api2.pushdeer.com/message/push'
response = requests.post(url, data=data).json()
if len(response.get("content").get("result")) > 0:
print("PushDeer 推送成功!")
else:
print("PushDeer 推送失败!错误信息:", response)
def pushplus_bot(title: str, content: str) -> None:
"""
通过 push+ 推送消息。
"""
if not push_config.get("PUSH_PLUS_TOKEN"):
print("PUSHPLUS 服务的 PUSH_PLUS_TOKEN 未设置!!\n取消推送")
return
print("PUSHPLUS 服务启动")
url = "http://www.pushplus.plus/send"
data = {
"token": push_config.get("PUSH_PLUS_TOKEN"),
"title": title,
"content": content,
"topic": push_config.get("PUSH_PLUS_USER"),
}
body = json.dumps(data).encode(encoding="utf-8")
headers = {"Content-Type": "application/json"}
response = requests.post(url=url, data=body, headers=headers).json()
if response["code"] == 200:
print("PUSHPLUS 推送成功!")
else:
url_old = "http://pushplus.hxtrip.com/send"
headers["Accept"] = "application/json"
response = requests.post(url=url_old, data=body, headers=headers).json()
if response["code"] == 200:
print("PUSHPLUS(hxtrip) 推送成功!")
else:
print("PUSHPLUS 推送失败!")
def qmsg_bot(title: str, content: str) -> None:
"""
使用 qmsg 推送消息。
"""
if not push_config.get("QMSG_KEY") or not push_config.get("QMSG_TYPE"):
print("qmsg 的 QMSG_KEY 或者 QMSG_TYPE 未设置!!\n取消推送")
return
print("qmsg 服务启动")
url = f'https://qmsg.zendee.cn/{push_config.get("QMSG_TYPE")}/{push_config.get("QMSG_KEY")}'
payload = {"msg": f'{title}\n\n{content.replace("----", "-")}'.encode("utf-8")}
response = requests.post(url=url, params=payload).json()
if response["code"] == 0:
print("qmsg 推送成功!")
else:
print(f'qmsg 推送失败!{response["reason"]}')
def wecom_app(title: str, content: str) -> None:
"""
通过 企业微信 APP 推送消息。
"""
if not push_config.get("QYWX_AM"):
print("QYWX_AM 未设置!!\n取消推送")
return
QYWX_AM_AY = re.split(",", push_config.get("QYWX_AM"))
if 4 < len(QYWX_AM_AY) > 5:
print("QYWX_AM 设置错误!!\n取消推送")
return
print("企业微信 APP 服务启动")
corpid = QYWX_AM_AY[0]
corpsecret = QYWX_AM_AY[1]
touser = QYWX_AM_AY[2]
agentid = QYWX_AM_AY[3]
try:
media_id = QYWX_AM_AY[4]
except IndexError:
media_id = ""
wx = WeCom(corpid, corpsecret, agentid)
# 如果没有配置 media_id 默认就以 text 方式发送
if not media_id:
message = title + "\n\n" + content
response = wx.send_text(message, touser)
else:
response = wx.send_mpnews(title, content, media_id, touser)
if response == "ok":
print("企业微信推送成功!")
else:
print("企业微信推送失败!错误信息如下:\n", response)
class WeCom:
def __init__(self, corpid, corpsecret, agentid):
self.CORPID = corpid
self.CORPSECRET = corpsecret
self.AGENTID = agentid
def get_access_token(self):
url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
values = {
"corpid": self.CORPID,
"corpsecret": self.CORPSECRET,
}
req = requests.post(url, params=values)
data = json.loads(req.text)
return data["access_token"]
def send_text(self, message, touser="@all"):
send_url = (
"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="
+ self.get_access_token()
)
send_values = {
"touser": touser,
"msgtype": "text",
"agentid": self.AGENTID,
"text": {"content": message},
"safe": "0",
}
send_msges = bytes(json.dumps(send_values), "utf-8")
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
def send_mpnews(self, title, message, media_id, touser="@all"):
send_url = (
"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="
+ self.get_access_token()
)
send_values = {
"touser": touser,
"msgtype": "mpnews",
"agentid": self.AGENTID,
"mpnews": {
"articles": [
{
"title": title,
"thumb_media_id": media_id,
"author": "Author",
"content_source_url": "",
"content": message.replace("\n", "<br/>"),
"digest": message,
}
]
},
}
send_msges = bytes(json.dumps(send_values), "utf-8")
respone = requests.post(send_url, send_msges)
respone = respone.json()
return respone["errmsg"]
def wecom_bot(title: str, content: str) -> None:
"""
通过 企业微信机器人 推送消息。
"""
if not push_config.get("QYWX_KEY"):
print("企业微信机器人 服务的 QYWX_KEY 未设置!!\n取消推送")
return
print("企业微信机器人服务启动")
url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={push_config.get('QYWX_KEY')}"
headers = {"Content-Type": "application/json;charset=utf-8"}
data = {"msgtype": "text", "text": {"content": f"{title}\n\n{content}"}}
response = requests.post(
url=url, data=json.dumps(data), headers=headers, timeout=15
).json()
if response["errcode"] == 0:
print("企业微信机器人推送成功!")
else:
print("企业微信机器人推送失败!")
def telegram_bot(title: str, content: str) -> None:
"""
使用 telegram 机器人 推送消息。
"""
if not push_config.get("TG_BOT_TOKEN") or not push_config.get("TG_USER_ID"):
print("tg 服务的 bot_token 或者 user_id 未设置!!\n取消推送")
return
print("tg 服务启动")
if push_config.get("TG_API_HOST"):
url = f"https://{push_config.get('TG_API_HOST')}/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
else:
url = (
f"https://api.telegram.org/bot{push_config.get('TG_BOT_TOKEN')}/sendMessage"
)
headers = {"Content-Type": "application/x-www-form-urlencoded"}
payload = {
"chat_id": str(push_config.get("TG_USER_ID")),
"text": f"{title}\n\n{content}",
"disable_web_page_preview": "true",
}
proxies = None
if push_config.get("TG_PROXY_HOST") and push_config.get("TG_PROXY_PORT"):
if push_config.get("TG_PROXY_AUTH") is not None and "@" not in push_config.get(
"TG_PROXY_HOST"
):
push_config["TG_PROXY_HOST"] = (
push_config.get("TG_PROXY_AUTH")
+ "@"
+ push_config.get("TG_PROXY_HOST")
)
proxyStr = "http://{}:{}".format(
push_config.get("TG_PROXY_HOST"), push_config.get("TG_PROXY_PORT")
)
proxies = {"http": proxyStr, "https": proxyStr}
response = requests.post(
url=url, headers=headers, params=payload, proxies=proxies
).json()
if response["ok"]:
print("tg 推送成功!")
else:
print("tg 推送失败!")
def one() -> str:
"""
获取一条一言。
:return:
"""
url = "https://v1.hitokoto.cn/"
res = requests.get(url).json()
return res["hitokoto"] + " ----" + res["from"]
if push_config.get("BARK_PUSH"):
notify_function.append(bark)
if push_config.get("CONSOLE"):
notify_function.append(console)
if push_config.get("DD_BOT_TOKEN") and push_config.get("DD_BOT_SECRET"):
notify_function.append(dingding_bot)
if push_config.get("FSKEY"):
notify_function.append(feishu_bot)
if push_config.get("GOBOT_URL") and push_config.get("GOBOT_QQ"):
notify_function.append(go_cqhttp)
if push_config.get("GOTIFY_URL") and push_config.get("GOTIFY_TOKEN"):
notify_function.append(gotify)
if push_config.get("IGOT_PUSH_KEY"):
notify_function.append(iGot)
if push_config.get("PUSH_KEY"):
notify_function.append(serverJ)
if push_config.get("DEER_KEY"):
notify_function.append(pushdeer)
if push_config.get("PUSH_PLUS_TOKEN"):
notify_function.append(pushplus_bot)
if push_config.get("QMSG_KEY") and push_config.get("QMSG_TYPE"):
notify_function.append(qmsg_bot)
if push_config.get("QYWX_AM"):
notify_function.append(wecom_app)
if push_config.get("QYWX_KEY"):
notify_function.append(wecom_bot)
if push_config.get("TG_BOT_TOKEN") and push_config.get("TG_USER_ID"):
notify_function.append(telegram_bot)
def send(title: str, content: str) -> None:
if not content:
print(f"{title} 推送内容为空!")
return
hitokoto = push_config.get("HITOKOTO")
text = one() if hitokoto else ""
content += "\n\n" + text
ts = [
threading.Thread(target=mode, args=(title, content), name=mode.__name__)
for mode in notify_function
]
[t.start() for t in ts]
[t.join() for t in ts]
def main():
send("title", "content")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,483 @@
# Source: https://github.com/DearSong15/ql-scripts/blob/main/ks_query.py
# Raw: https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_query.py
# Repo: DearSong15/ql-scripts
# Path: ks_query.py
# UploadedAt: 2026-05-11T14:51:55Z
# SHA256: 848504df99018b6b2f9d7bac940671dc65777b8d973c1610e2a3111c88d36480
# Category: web版/抓包
# Evidence: web/H5关键词 + cookie/token/header
import json
import os
import requests
import time
from datetime import datetime, timedelta
from openpyxl import Workbook
from openpyxl.styles import Alignment, Font, PatternFill
def print_disclaimer():
"""打印免责声明"""
print("=" * 60)
print("【免责声明】")
print("1. 本程序仅为技术学习和个人账号信息查询使用,请勿用于商业用途或非法操作。")
print("2. 使用本程序需确保您对所查询的快手账号拥有合法所有权或使用权,严禁查询他人账号信息。")
print("3. 快手平台API可能随时变更导致程序无法正常运行开发者不保证程序的稳定性和可用性。")
print("4. 任何因使用本程序违反快手平台用户协议、法律法规或侵犯他人权益的行为,均由使用者自行承担全部责任。")
print("5. 开发者对使用本程序产生的任何直接或间接损失不承担任何法律责任。")
print("6. 本程序为临时查询工具建议您在使用完毕后24小时内删除程序及相关账号配置信息以保障账号安全。")
print("确认了解并同意以上条款后,程序将继续运行...")
print("快手极速版以及普通版本cookie有的账号是通用的普通版(kpn=KUAISHOU) 极速版(kpn=NEBULA)更改cookie的kpn即可")
print("\n请设置环境变量 ksck格式为:")
print("备注#cookie#salt#ip|端口|用户名|密码|到期日期")
print("=" * 60 + "\n")
# 比率映射关系
RATIO_MAP = {
19: 0.00009,
28: 0.00008,
37: 0.00007,
46: 0.00006,
55: 0.00005,
64: 0.00004,
73: 0.00003,
82: 0.00002,
91: 0.00001
}
# 读取环境变量中的参数默认46
SELECTED_PARAM = int(os.getenv("RATIO_PARAM", 46))
class KuaishouClient:
def __init__(self, index, cookie, remark=""):
self.index = index
self.remark = remark
self.cookie = cookie
self.user_name = "未知用户"
# 余额信息
self.coin_balance = 0
self.cash_balance = 0
self.total_balance = 0
# 今日和昨日金币
self.today_coin = 0
self.yesterday_coin = 0
# 兑换后金额
self.today_coin_cash = 0
self.yesterday_coin_cash = 0
# 流水记录
self.coin_records = []
self.cash_records = []
# 基础配置
self.headers = {
'User-Agent': "Mozilla/5.0 (Linux; Android 16; PTP-AN00 Build/HONORPTP-AN00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/139.0.7258.158 Mobile Safari/537.36 Yoda/3.2.17-rc2 Kwai/13.9.30.44872 OS_PRO_BIT/64 MAX_PHY_MEM/15272 KDT/PHONE AZPREFIX/az1 ICFO/0 StatusHT/38 TitleHT/44 NetType/NR ISLP/0 ISDM/0 ISLB/0 locale/zh-cn SHP/2665 SWP/1264 SD/3.5 CT/0 ISLM/0",
'Accept-Encoding': "gzip, deflate, br, zstd",
'sec-ch-ua-platform': "\"Android\"",
'sec-ch-ua': "\"Not;A=Brand\";v=\"99\", \"Android WebView\";v=\"139\", \"Chromium\";v=\"139\"",
'sec-ch-ua-mobile': "?1",
'X-Requested-With': "com.smile.gifmaker",
'Sec-Fetch-Site': "same-origin",
'Sec-Fetch-Mode': "cors",
'Sec-Fetch-Dest': "empty",
'Referer': "https://encourage.kuaishou.com/kwai/profit?tab=coin&layoutType=4",
'Accept-Language': "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
'Cookie': self.cookie
}
def send_request(self, url, method="get", params=None):
"""发送请求"""
try:
if method == "get":
response = requests.get(url, headers=self.headers, params=params, timeout=10)
else:
response = requests.post(url, headers=self.headers, data=params, timeout=10)
if response.status_code == 200:
return response.json()
else:
print(f"请求失败,状态码: {response.status_code}")
return None
except Exception as e:
print(f"请求异常: {e}")
return None
def query_withdraw_info(self):
"""查询提现信息(包含用户名和余额)"""
url = "https://encourage.kuaishou.com/rest/wd/encourage/account/withdraw/info"
params = {
"source": "normal",
"imei": "",
"oaid": "279b0911-a941-4e80-b5fd-91f1c1ea2644",
"idfa": ""
}
result = self.send_request(url, params=params)
if result and result.get("result") == 1:
data = result.get("data", {})
# 获取用户名
self.user_name = data.get("nickname", "未知用户")
# 获取账户信息
account = data.get("account", {})
self.coin_balance = account.get("coinAmount", 0)
self.cash_balance = account.get("cashAmount", 0) # 单位:分
self.total_balance = account.get("accumulativeAmount", 0) # 单位:分
return True
return False
def query_cash_records(self):
"""查询现金流水记录"""
url = "https://encourage.kuaishou.com/rest/wd/encourage/account/detail"
params = {
"__NS_sig3": "6272350512f90404a43e5b3d3a3b5b3320a219ee1616ba201b5f2d2d2b2b28291636",
"sigCatVer": "1",
"accountType": "cash",
"cursor": ""
}
result = self.send_request(url, params=params)
if result and result.get("result") == 1:
data = result.get("data", {})
records = data.get("datas", [])
for record in records[:3]:
self.cash_records.append({
'time': self._format_timestamp(record.get("createTime", 0)),
'title': record.get("title", ""),
'amount': record.get("displayAmount", "0"),
'direction': record.get("direction", "")
})
return True
return False
def query_coin_records(self):
"""查询金币流水记录"""
url = "https://encourage.kuaishou.com/rest/wd/encourage/account/detail"
params = {
"__NS_sig3": "7262251502e91414b42e4a2d2a2b6006895f03fe0606aa3024c33d3d3b3b38390626",
"sigCatVer": "1",
"accountType": "coin",
"cursor": ""
}
result = self.send_request(url, params=params)
if result and result.get("result") == 1:
data = result.get("data", {})
records = data.get("datas", [])
for record in records[:3]:
self.coin_records.append({
'time': self._format_timestamp(record.get("createTime", 0)),
'title': record.get("title", ""),
'amount': record.get("displayAmount", "0"),
'direction': record.get("direction", "")
})
return True
return False
def _format_timestamp(self, timestamp):
"""格式化时间戳"""
if timestamp:
try:
dt = datetime.fromtimestamp(timestamp / 1000)
return dt.strftime("%Y-%m-%d %H:%M")
except:
return "未知时间"
return "未知时间"
def calculate_coin_stats(self):
"""计算今日和昨日金币收入及兑换后金额"""
today = datetime.now().date()
yesterday = today - timedelta(days=1)
self.today_coin = 0
self.yesterday_coin = 0
url = "https://encourage.kuaishou.com/rest/wd/encourage/account/detail"
params = {
"__NS_sig3": "7262251502e91414b42e4a2d2a2b6006895f03fe0606aa3024c33d3d3b3b38390626",
"sigCatVer": "1",
"accountType": "coin",
"cursor": ""
}
result = self.send_request(url, params=params)
if result and result.get("result") == 1:
data = result.get("data", {})
records = data.get("datas", [])
for record in records:
if record.get("direction") != "IN":
continue
amount = record.get("amount", 0)
create_time = record.get("createTime", 0)
if create_time:
record_date = datetime.fromtimestamp(create_time / 1000).date()
if record_date == today:
self.today_coin += amount
elif record_date == yesterday:
self.yesterday_coin += amount
# 计算兑换后金额
ratio = RATIO_MAP.get(SELECTED_PARAM, 0.00006) # 默认46对应的比率
self.today_coin_cash = round(self.today_coin * ratio, 2)
self.yesterday_coin_cash = round(self.yesterday_coin * ratio, 2)
return True
def query_all_data(self):
"""查询所有数据"""
print(f"正在查询账号[{self.index}] {self.remark}...")
# 查询提现信息(包含用户名和余额)
if not self.query_withdraw_info():
print(f"账号[{self.index}] {self.remark} 提现信息查询失败")
return False
# 查询现金流水
if not self.query_cash_records():
print(f"账号[{self.index}] {self.remark} 现金流水查询失败")
# 查询金币流水
if not self.query_coin_records():
print(f"账号[{self.index}] {self.remark} 金币流水查询失败")
# 计算金币统计
self.calculate_coin_stats()
return True
def get_display_data(self):
"""获取显示数据"""
# 现金余额从分转换为元
cash_yuan = self.cash_balance / 100 if self.cash_balance else 0
total_yuan = self.total_balance / 100 if self.total_balance else 0
return {
"index": self.index,
"user_name": self.user_name,
"remark": self.remark,
"today_coin": self.today_coin,
"yesterday_coin": self.yesterday_coin,
"today_coin_cash": self.today_coin_cash,
"yesterday_coin_cash": self.yesterday_coin_cash,
"coin_balance": self.coin_balance,
"cash_balance": round(cash_yuan, 2),
"total_balance": round(total_yuan, 2),
"coin_records": self.coin_records,
"cash_records": self.cash_records,
"ratio_param": SELECTED_PARAM
}
def load_cookies_from_env():
"""从环境变量ksck加载cookie配置格式备注#cookie#salt#ip|端口|用户名|密码|到期日期"""
cookies = []
ksck_env = os.getenv('ksck')
if not ksck_env:
print("未找到环境变量 ksck")
return cookies
lines = ksck_env.strip().split('&')
for i, line in enumerate(lines):
line = line.strip()
if not line:
continue
parts = line.split('#')
if len(parts) < 3:
print(f"{i + 1}行格式错误,跳过: {line}")
continue
remark = parts[0].strip()
cookie = parts[1].strip()
salt = parts[2].strip() # 暂时不使用
if not cookie:
print(f"{i + 1}行cookie为空跳过")
continue
# 不再检查socName直接添加
cookies.append({
"cookie": cookie,
"remark": remark
})
print(f"从环境变量 ksck 加载了 {len(cookies)} 个账号")
return cookies
def create_excel_summary(data_list, filename="快手金币数据汇总.xlsx"):
"""创建Excel汇总表格"""
wb = Workbook()
ws = wb.active
ws.title = "金币数据汇总"
# 设置表头
headers = ["序号", "用户名", "备注", "今日金币", "昨日金币", "当前金币",
f"今日{SELECTED_PARAM}后(元)", f"昨日{SELECTED_PARAM}后(元)", "当前现金(元)", "累计收益(元)",
"最近金币流水", "最近现金流水"]
for col, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col)
cell.value = header
cell.font = Font(bold=True)
cell.alignment = Alignment(horizontal="center")
cell.fill = PatternFill(start_color="E6F3FF", end_color="E6F3FF", fill_type="solid")
# 填充数据
for row, data in enumerate(data_list, 2):
ws.cell(row=row, column=1, value=data["index"]).alignment = Alignment(horizontal="center")
ws.cell(row=row, column=2, value=data["user_name"])
ws.cell(row=row, column=3, value=data["remark"])
ws.cell(row=row, column=4, value=data["today_coin"]).alignment = Alignment(horizontal="right")
ws.cell(row=row, column=5, value=data["yesterday_coin"]).alignment = Alignment(horizontal="right")
ws.cell(row=row, column=6, value=data["coin_balance"]).alignment = Alignment(horizontal="right")
ws.cell(row=row, column=7, value=data["today_coin_cash"]).alignment = Alignment(horizontal="right")
ws.cell(row=row, column=8, value=data["yesterday_coin_cash"]).alignment = Alignment(horizontal="right")
ws.cell(row=row, column=9, value=data["cash_balance"]).alignment = Alignment(horizontal="right")
ws.cell(row=row, column=10, value=data["total_balance"]).alignment = Alignment(horizontal="right")
# 格式化流水记录
coin_flow = "\n".join([f"{r['time']} {r['title']} +{r['amount']}" for r in data["coin_records"]])
cash_flow = "\n".join([f"{r['time']} {r['title']} {r['amount']}" for r in data["cash_records"]])
ws.cell(row=row, column=11, value=coin_flow)
ws.cell(row=row, column=12, value=cash_flow)
# 设置列宽
column_widths = {
'A': 8, # 序号
'B': 20, # 用户名
'C': 20, # 备注
'D': 12, # 今日金币
'E': 12, # 昨日金币
'F': 12, # 当前金币
'G': 18, # 今日兑换后
'H': 18, # 昨日兑换后
'I': 15, # 当前现金
'J': 15, # 累计收益
'K': 30, # 最近金币流水
'L': 30 # 最近现金流水
}
for col, width in column_widths.items():
ws.column_dimensions[col].width = width
# 设置行高
for row in range(2, len(data_list) + 2):
ws.row_dimensions[row].height = 60
# 保存文件
wb.save(filename)
print(f"\nExcel表格已生成: {filename}")
# 打印汇总统计
total_today = sum(data["today_coin"] for data in data_list)
total_yesterday = sum(data["yesterday_coin"] for data in data_list)
total_today_cash = sum(data["today_coin_cash"] for data in data_list)
total_yesterday_cash = sum(data["yesterday_coin_cash"] for data in data_list)
total_coins = sum(data["coin_balance"] for data in data_list)
total_cash = sum(data["cash_balance"] for data in data_list)
total_accumulative = sum(data["total_balance"] for data in data_list)
ratio = RATIO_MAP.get(SELECTED_PARAM, 0.00006)
print(f"\n汇总统计 (使用比率参数 {SELECTED_PARAM}, 比率: {ratio}):")
print(f"今日金币总数: {total_today}")
print(f"今日金币兑换后: {total_today_cash}")
print(f"昨日金币总数: {total_yesterday}")
print(f"昨日金币兑换后: {total_yesterday_cash}")
print(f"当前金币总数: {total_coins}")
print(f"当前现金总数: {total_cash}")
print(f"累计收益总数: {total_accumulative}")
def main():
"""主函数"""
print_disclaimer()
print("开始查询快手账号数据...")
print("=" * 50)
print(f"当前使用比率参数: {SELECTED_PARAM}, 兑换比率: {RATIO_MAP.get(SELECTED_PARAM, 0.00006)}")
print("=" * 50)
# 从环境变量加载cookie配置
cookies_config = load_cookies_from_env()
if not cookies_config:
print("错误: 未找到有效的cookie配置")
print("\n请设置环境变量 ksck格式为:")
print("备注#cookie#salt#ip|端口|用户名|密码|到期日期")
print("每行一个账号,用&分隔,例如:")
print("我的账号1#kuaishou.api_st=xxx; token=xxx#salt1#&我的账号2#kuaishou.api_st=yyy; token=yyy#salt2#")
return
all_data = []
success_count = 0
for i, account in enumerate(cookies_config):
if not account.get("cookie"):
print(f"账号[{i + 1}] cookie为空跳过")
continue
client = KuaishouClient(
index=i + 1,
cookie=account["cookie"],
remark=account["remark"]
)
if client.query_all_data():
data = client.get_display_data()
all_data.append(data)
success_count += 1
# 打印单个账号信息
print(f"\n账号[{i + 1}] 用户名: {data['user_name']} 备注: {account['remark']} 查询成功:")
print(f" 今日金币: {data['today_coin']}{data['today_coin_cash']}")
print(f" 昨日金币: {data['yesterday_coin']}{data['yesterday_coin_cash']}")
print(f" 当前金币: {data['coin_balance']}")
print(f" 当前现金: {data['cash_balance']}")
print(f" 累计收益: {data['total_balance']}")
if data['coin_records']:
print(" 最近金币流水:")
for record in data['coin_records']:
print(f" {record['time']} {record['title']} +{record['amount']}")
if data['cash_records']:
print(" 最近现金流水:")
for record in data['cash_records']:
print(f" {record['time']} {record['title']} {record['amount']}")
else:
print(f"\n账号[{i + 1}] {account['remark']} 查询失败")
# 添加0.5秒延迟,避免请求过于频繁
if i < len(cookies_config) - 1: # 最后一个账号不需要延迟
print("等待0.5秒后继续下一个账号...")
time.sleep(0.5)
# 生成Excel表格
if all_data:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"快手金币数据汇总_{SELECTED_PARAM}后_{timestamp}.xlsx"
create_excel_summary(all_data, filename)
print(f"\n成功查询 {success_count}/{len(cookies_config)} 个账号")
else:
print("没有成功查询到任何账号数据")
if __name__ == "__main__":
main()

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,563 @@
// # Source: https://github.com/huwangkeji/juejin_checkin/blob/main/juejin_checkin.js
// # Raw: https://raw.githubusercontent.com/huwangkeji/juejin_checkin/main/juejin_checkin.js
// # Repo: huwangkeji/juejin_checkin
// # Path: juejin_checkin.js
// # UploadedAt: 2026-05-19T14:34:11Z
// # SHA256: 6f8a138b51c397220444c9312040dbe3407af5aeed4fa4467a36672aeb8bcfd1
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
/*
* @name 掘金自动签到脚本
* @description 掘金社区每日签到 + 免费抽奖 + 沾喜气 + Bug消除支持Cookie自动签到
* @namespace https://juejin.cn
* @version 1.0.0
* @author CodeBuddy
*
* 【青龙面板使用说明】
* 1. 依赖管理 -> NodeJS -> 添加依赖: axios
* 2. 环境变量 (必填):
* - JUEJIN_COOKIE: 掘金Cookie (从浏览器开发者工具复制)
* - JUEJIN_AID: API参数aid (通常为2608)
* - JUEJIN_UUID: API参数uuid
* - JUEJIN_MSTOKEN: API参数msToken
* - JUEJIN_A_BOGUS: API参数a_bogus
* 3. 环境变量 (可选):
* - JUEJIN_COOKIE_2 ~ JUEJIN_COOKIE_5: 多账号Cookie
* - JUEJIN_NOTIFY: 是否推送通知 (默认true)
* 4. 定时规则: 30 6 * * * (每天早上6:30执行)
*
* 【参数获取方式】
* 1. 浏览器打开 https://juejin.cn 并登录
* 2. 按F12打开开发者工具 -> Network(网络)标签
* 3. 刷新页面,找到任意一个 api.juejin.cn 的请求
* 4. 在 Request Headers 中复制完整的 Cookie 值
* 5. 在 Query String Parameters 中复制 aid, uuid, msToken, a_bogus
* 6. 粘贴到青龙面板对应的环境变量中
* 7. Cookie和参数有效期约30天过期后需重新获取
*
* 【功能列表】
* - Cookie自动签到支持多账号
* - 每日签到
* - 免费抽奖
* - 沾喜气
* - Bug消除
* - 查询矿石余额/签到天数/幸运值
* - 青龙面板通知推送
*/
const axios = require('axios');
// ==================== 配置区域 ====================
const API_BASE = 'https://api.juejin.cn';
// 请求头
const DEFAULT_HEADERS = {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
'Referer': 'https://juejin.cn/',
'Origin': 'https://juejin.cn',
'Content-Type': 'application/json',
'sec-ch-ua': '"Not/A)Brand";v="99", "Chromium";v="148"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
};
// ==================== 工具函数 ====================
function log(msg) {
const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
console.log(`[${now}] ${msg}`);
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* 创建带Cookie和参数的axios实例
*/
function createApiClient(cookie, params) {
const instance = axios.create({
baseURL: API_BASE,
headers: {
...DEFAULT_HEADERS,
Cookie: cookie,
},
timeout: 30000,
});
// 请求拦截 - 自动添加查询参数
instance.interceptors.request.use((config) => {
if (params && Object.keys(params).length > 0) {
config.params = { ...config.params, ...params };
}
// POST请求body为空对象
if (config.method === 'post' && !config.data) {
config.data = {};
}
return config;
});
// 响应拦截
instance.interceptors.response.use(
(response) => {
const data = response.data;
// 处理空响应
if (data === '' || data === null || data === undefined) {
throw new Error('API返回空响应可能需要更新参数');
}
if (typeof data === 'object' && data.err_no !== 0) {
throw new Error(`API错误: [${data.err_no}] ${data.err_msg || '未知错误'}`);
}
return data.data;
},
(error) => {
if (error.response) {
const data = error.response.data;
if (data && typeof data === 'object' && data.err_no !== undefined) {
throw new Error(`API错误: [${data.err_no}] ${data.err_msg || '未知错误'}`);
}
throw new Error(`HTTP错误: ${error.response.status} ${error.response.statusText}`);
}
throw error;
}
);
return instance;
}
// ==================== API 调用 ====================
/**
* 检查今日签到状态
*/
async function getTodayStatus(api) {
try {
const data = await api.get('/growth_api/v1/get_today_status');
return data === true;
} catch (e) {
log('⚠️ 查询签到状态失败: ' + e.message);
return null;
}
}
/**
* 执行签到
*/
async function checkIn(api) {
try {
const data = await api.post('/growth_api/v1/check_in');
log('✅ 签到成功!');
return { success: true, data };
} catch (e) {
if (e.message.includes('15001') || e.message.includes('已签到') || e.message.includes('duplicate')) {
log('📌 今日已签到,无需重复签到');
return { success: true, already: true };
}
if (e.message.includes('3013')) {
log('📌 今日已签到 (3013)');
return { success: true, already: true };
}
if (e.message.includes('空响应')) {
log('⚠️ API返回空响应参数可能已过期建议重新获取');
return { success: false, error: e.message };
}
log('❌ 签到失败: ' + e.message);
return { success: false, error: e.message };
}
}
/**
* 获取签到天数统计
*/
async function getCounts(api) {
try {
const data = await api.get('/growth_api/v1/get_counts');
return data;
} catch (e) {
log('⚠️ 获取签到统计失败: ' + e.message);
return null;
}
}
/**
* 获取当前矿石数
*/
async function getCurrentPoint(api) {
try {
const data = await api.get('/growth_api/v1/get_cur_point');
return data;
} catch (e) {
log('⚠️ 获取矿石余额失败: ' + e.message);
return null;
}
}
/**
* 获取抽奖配置
*/
async function getLotteryConfig(api) {
try {
const data = await api.get('/growth_api/v1/lottery_config/get');
return data;
} catch (e) {
log('⚠️ 获取抽奖配置失败: ' + e.message);
return null;
}
}
/**
* 免费抽奖
*/
async function drawLottery(api) {
try {
const data = await api.post('/growth_api/v1/lottery/draw');
log('🎉 抽奖成功!奖品: ' + (data.lottery_name || '未知'));
return { success: true, data };
} catch (e) {
log('❌ 抽奖失败: ' + e.message);
return { success: false, error: e.message };
}
}
/**
* 沾喜气
*/
async function dipLucky(api) {
try {
// 先获取幸运用户列表
const luckyUsers = await api.post('/growth_api/v1/lottery_history/global_big', {
page_no: 1,
page_size: 5,
});
if (luckyUsers && luckyUsers.lotteries && luckyUsers.lotteries.length > 0) {
const historyId = luckyUsers.lotteries[0].history_id;
const data = await api.post('/growth_api/v1/lottery_lucky/dip_lucky', {
lottery_history_id: historyId,
});
log('🍀 沾喜气成功!幸运值: ' + (data.dip_value || 0));
return { success: true, data };
}
log('⚠️ 暂无可沾喜气的用户');
return { success: false };
} catch (e) {
log('❌ 沾喜气失败: ' + e.message);
return { success: false, error: e.message };
}
}
/**
* 获取我的幸运值
*/
async function getMyLucky(api) {
try {
const data = await api.post('/growth_api/v1/lottery_lucky/my_lucky');
return data;
} catch (e) {
log('⚠️ 获取幸运值失败: ' + e.message);
return null;
}
}
/**
* 查询用户信息 (验证Cookie有效性)
*/
async function getUserInfo(api) {
try {
const data = await api.get('/user_api/v1/user/get');
return data;
} catch (e) {
log('⚠️ Cookie无效或已过期: ' + e.message);
return null;
}
}
/**
* 获取Bug消除配置
*/
async function getBugFixConfig(api) {
try {
const data = await api.get('/growth_api/v1/bugfix/not_collect');
return data;
} catch (e) {
log('⚠️ 获取Bug配置失败: ' + e.message);
return null;
}
}
/**
* 消除Bug
*/
async function fixBug(api, bugId) {
try {
const data = await api.post('/growth_api/v1/bugfix/collect', {
bug_type: bugId,
});
log('🐛 Bug消除成功');
return { success: true, data };
} catch (e) {
log('❌ Bug消除失败: ' + e.message);
return { success: false, error: e.message };
}
}
// ==================== 青龙面板通知 ====================
/**
* 青龙面板通知推送
*/
async function sendNotify(title, content) {
if (process.env.JUEJIN_NOTIFY === 'false') {
log('📢 通知已禁用');
return;
}
try {
// 尝试加载青龙面板的通知模块
const notifyPath = require('path').join(process.cwd(), 'notify.js');
if (require('fs').existsSync(notifyPath)) {
const sendNotifyFn = require(notifyPath);
if (typeof sendNotifyFn === 'function') {
await sendNotifyFn(title, content);
log('📢 青龙通知已发送');
return;
}
}
// 尝试从全局加载
try {
const { sendNotify: qinglongNotify } = require('qlnotify');
await qinglongNotify(title, content);
log('📢 青龙通知已发送');
return;
} catch (e) {
// 忽略
}
log('📢 青龙通知模块未找到,仅控制台输出');
} catch (e) {
log('⚠️ 发送通知失败: ' + e.message);
}
}
// ==================== 单个账号签到流程 ====================
async function runAccount(cookie, params, index) {
const prefix = index > 1 ? `[账号${index}] ` : '';
log('');
log(`${prefix}═══════════════════════════════════════`);
log(`${prefix} 开始处理账号 ${index}`);
log(`${prefix}═══════════════════════════════════════`);
if (!cookie || cookie.trim().length === 0) {
log(`${prefix}❌ Cookie为空跳过`);
return null;
}
// 创建API客户端
const api = createApiClient(cookie, params);
// 验证Cookie有效性
log(`${prefix}🔍 验证Cookie...`);
const userInfo = await getUserInfo(api);
if (!userInfo) {
log(`${prefix}❌ Cookie已失效请重新获取`);
return {
success: false,
error: 'Cookie已失效',
userName: '未知用户',
};
}
const userName = userInfo.user_name || userInfo.nick_name || '未知用户';
log(`${prefix}✅ Cookie有效用户: ${userName}`);
// 签到
log(`${prefix}📅 执行签到...`);
const todayStatus = await getTodayStatus(api);
let signInResult = { success: true, already: todayStatus === true };
if (todayStatus === true) {
log(`${prefix}📌 今日已签到,跳过`);
} else if (todayStatus === false) {
signInResult = await checkIn(api);
if (!signInResult.success) {
log(`${prefix}🔄 签到失败1秒后重试...`);
await sleep(1000);
signInResult = await checkIn(api);
}
} else {
log(`${prefix}⚠️ 无法查询签到状态,直接尝试签到...`);
signInResult = await checkIn(api);
}
// 抽奖
log(`${prefix}🎰 执行抽奖...`);
const lotteryConfig = await getLotteryConfig(api);
let lotteryResult = { success: false };
if (lotteryConfig && lotteryConfig.free_count > 0) {
log(`${prefix}🎁 有 ${lotteryConfig.free_count} 次免费抽奖机会`);
lotteryResult = await drawLottery(api);
} else if (lotteryConfig) {
log(`${prefix}📌 今日免费抽奖次数已用完`);
}
// 沾喜气
log(`${prefix}🍀 沾喜气...`);
const dipResult = await dipLucky(api);
// Bug消除
log(`${prefix}🐛 消除Bug...`);
const bugConfig = await getBugFixConfig(api);
let bugFixResult = { success: false };
if (bugConfig && Array.isArray(bugConfig) && bugConfig.length > 0) {
const bug = bugConfig[0];
log(`${prefix}🔧 发现未消除的Bug: ${bug.bug_type}`);
bugFixResult = await fixBug(api, bug.bug_type);
} else {
log(`${prefix}📌 暂无Bug可消除`);
}
// 查询统计信息
log(`${prefix}📊 查询统计...`);
const counts = await getCounts(api);
const point = await getCurrentPoint(api);
const lucky = await getMyLucky(api);
if (counts) {
log(`${prefix}📅 连续签到: ${counts.cont_count || 0}`);
log(`${prefix}📅 累计签到: ${counts.sum_count || 0}`);
}
if (point !== null) {
log(`${prefix}💰 当前矿石: ${point}`);
}
if (lucky) {
log(`${prefix}🍀 幸运值: ${lucky.total_value || 0}`);
}
log(`${prefix}✅ 账号处理完成`);
return {
success: true,
userName,
signIn: signInResult,
lottery: lotteryResult,
dip: dipResult,
bugFix: bugFixResult,
counts,
point,
lucky,
};
}
// ==================== 主流程 ====================
async function main() {
log('═══════════════════════════════════════');
log(' 掘金自动签到脚本 v1.0.0');
log('═══════════════════════════════════════');
// 收集所有账号的配置
const accounts = [];
// 主账号
const mainCookie = process.env.JUEJIN_COOKIE || '';
const mainParams = {
aid: process.env.JUEJIN_AID || '2608',
uuid: process.env.JUEJIN_UUID || '',
msToken: process.env.JUEJIN_MSTOKEN || '',
a_bogus: process.env.JUEJIN_A_BOGUS || '',
spider: '0',
};
if (mainCookie) {
accounts.push({ cookie: mainCookie, params: mainParams });
}
// 多账号支持
for (let i = 2; i <= 5; i++) {
const cookie = process.env[`JUEJIN_COOKIE_${i}`] || '';
if (cookie) {
accounts.push({
cookie,
params: {
aid: process.env[`JUEJIN_AID_${i}`] || mainParams.aid,
uuid: process.env[`JUEJIN_UUID_${i}`] || '',
msToken: process.env[`JUEJIN_MSTOKEN_${i}`] || '',
a_bogus: process.env[`JUEJIN_A_BOGUS_${i}`] || '',
spider: '0',
},
});
}
}
if (accounts.length === 0) {
log('');
log('❌ 未配置Cookie请设置环境变量 JUEJIN_COOKIE');
log('');
log('【参数获取方式】');
log('1. 浏览器打开 https://juejin.cn 并登录');
log('2. 按F12打开开发者工具 -> Network(网络)标签');
log('3. 刷新页面,找到任意一个 api.juejin.cn 的请求');
log('4. 在 Request Headers 中复制完整的 Cookie 值');
log('5. 在 Query String Parameters 中复制 aid, uuid, msToken, a_bogus');
log('6. 粘贴到青龙面板对应的环境变量中');
log('');
process.exit(1);
}
log(`📱 共配置 ${accounts.length} 个账号`);
// 执行每个账号的签到
const results = [];
for (let i = 0; i < accounts.length; i++) {
const result = await runAccount(accounts[i].cookie, accounts[i].params, i + 1);
if (result) results.push(result);
}
// 生成通知内容
log('');
log('📢 发送通知...');
let notifyTitle = '掘金每日签到报告';
let notifyContent = '';
for (let i = 0; i < results.length; i++) {
const r = results[i];
const prefix = results.length > 1 ? `【账号${i + 1}` : '';
if (!r.success) {
notifyContent += `${prefix}${r.userName}: ${r.error}\n`;
continue;
}
notifyContent += `${prefix}👤 ${r.userName}\n`;
notifyContent += ` 📅 连续签到: ${r.counts?.cont_count || 0}\n`;
notifyContent += ` 📅 累计签到: ${r.counts?.sum_count || 0}\n`;
notifyContent += ` 💰 当前矿石: ${r.point ?? '未知'}\n`;
notifyContent += ` 🍀 幸运值: ${r.lucky?.total_value || 0}\n`;
notifyContent += ` ✅ 签到: ${r.signIn.already ? '今日已签到' : r.signIn.success ? '成功' : '失败'}\n`;
notifyContent += ` 🎰 抽奖: ${r.lottery.success ? '成功 - ' + (r.lottery.data?.lottery_name || '') : '未抽奖/失败'}\n`;
notifyContent += ` 🍀 沾喜气: ${r.dip.success ? '成功' : '失败'}\n`;
notifyContent += ` 🐛 Bug消除: ${r.bugFix.success ? '成功' : '无/失败'}\n`;
notifyContent += '\n';
}
await sendNotify(notifyTitle, notifyContent);
log('');
log('═══════════════════════════════════════');
log(' 脚本执行完成!');
log('═══════════════════════════════════════');
}
// 执行主函数
main().catch((error) => {
log('💥 脚本异常退出: ' + error.message);
console.error(error);
process.exit(1);
});

View File

@@ -0,0 +1,352 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/3dmgame.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/3dmgame.py
# Repo: lksky8/sign-ql
# Path: 3dmgame.py
# UploadedAt: 2026-03-27T20:17:30Z
# SHA256: 2262c9f7c2d40c8ef9822325fadd2e8ed3c43ba0f609c072a27c49b02edc2eaa
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
作者https://github.com/lksky8/sign-ql/
日期2026-3-28
网站3dmgame论坛签到
功能:签到、抽奖,金币可换现金买游戏
食用方法登录论坛后浏览器F12打开抓包https://bbs.3dmgame.com/home.php?mod=spacecp&ac=credit&showcredit=1抓这个url请求头的cookie包
变量bbs3dmck='cookie' 多个账号用换行分割
定时一天三次
青龙需要安装lxml模块
cron: 0 9 */8 * * *
"""
import time
import requests
from lxml import etree
import re
import random
import os
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'{cont}\n'
send_msg += f'{cont}\n'
# 发送通知消息
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
print('发送通知消息失败!' + str(e))
class ThreeDMGame:
def __init__(self, cookies):
headers = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'https://bbs.3dmgame.com',
'Pragma': 'no-cache',
'Sec-Fetch-Dest': 'iframe',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'same-origin',
'Sec-Fetch-User': '?1',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36',
'sec-ch-ua': '"Chromium";v="146", "Not-A.Brand";v="24", "Google Chrome";v="146"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'Cookie': cookies,
}
self.session = requests.Session()
self.session.headers.update(headers)
def user_info(self):
try:
response = self.session.get('https://bbs.3dmgame.com/home.php?mod=spacecp&ac=credit&showcredit=1')
html = etree.HTML(response.text)
user_id = html.xpath('//*[@id="hd"]/div/div[1]/p/strong/a/text()')[0]
points = html.xpath('//*[@id="extcreditmenu"]/text()')[0]
gold = html.xpath('//*[@id="ct"]/div[1]/div/ul[2]/li[1]/text()')[0]
print(f'用户ID[{user_id}] {points} 金元:{gold}')
Log(f'\n用户ID[{user_id}] {points} 金元:{gold}')
except Exception as e:
print('3dmgame论坛用户信息获取失败', e)
Log(f'\n3dmgame论坛用户信息获取失败')
def task_view(self, t_id):
try:
response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=view&id={t_id}')
html = etree.HTML(response.text)
task_name = html.xpath('//h1[contains(@class, "xs2") and contains(@class, "ptm") and contains(@class, "pbm")]/text()')[0].strip()
if 'do=apply' in response.text:
print(f'任务:《{task_name}》 可申请')
elif '后可以再次申请' in response.text:
print(f'任务:《{task_name}》 未到申请时间')
elif '您所在的用户组无法申请此任务' in response.text:
print(f'任务:《{task_name}》 您所在的用户组无法申请此任务')
elif 'static/image/task/reward.gif' in response.text:
print(f'任务:《{task_name}》 任务已完成,待领取奖励')
else:
print(f'任务:《{task_name}》 未知状态')
except Exception as e:
print(f'查看任务信息失败:{t_id} {e}')
def check_task(self):
try:
response = self.session.get('https://bbs.3dmgame.com/home.php?mod=task')
# print(response.text)
html = etree.HTML(response.text)
task_rows = html.xpath('//div[@class="ptm"]//table//tr')
# for row in task_rows:
# # 提取任务名称
# task_name = row.xpath('.//td[2]//h3/a/text()')[0] if row.xpath('.//td[2]//h3/a/text()') else ""
#
# # 提取任务描述
# description = row.xpath('.//td[2]/p/text()')[0] if row.xpath('.//td[2]/p/text()') else ""
#
# # 提取任务奖励
# reward = row.xpath('.//td[3]/text()')[0].strip() if row.xpath('.//td[3]/text()') else ""
#
# # 提取任务状态(可申请/不可申请)
# is_available = len(row.xpath('.//td[4]//img[@alt="apply"]')) > 0
#
# apply_link = row.xpath('.//td[4]/a[contains(@href, "do=apply")]/@href')[0] if row.xpath('.//td[4]/a[contains(@href, "do=apply")]/@href') else "无可用申请链接"
#
# print(f"任务名称: {task_name}")
# print(f"申请链接: {apply_link}")
# print(f"描述: {description}")
# print(f"奖励: {reward}")
# print(f"是否可申请: {'是' if is_available else '否'}")
# print("---")
task_list = {}
for row in task_rows:
task_name = row.xpath('.//td[2]//h3/a/text()')[0] if row.xpath('.//td[2]//h3/a/text()') else ""
description = row.xpath('.//td[2]/p/text()')[0] if row.xpath('.//td[2]/p/text()') else ""
reward = row.xpath('.//td[3]/text()')[0].strip() if row.xpath('.//td[3]/text()') else ""
apply_links = row.xpath('.//td[4]/a[contains(@href, "do=apply")]/@href')
# 只处理有可用申请链接的任务
if apply_links:
apply_link = apply_links[0]
print(f"任务名称: {task_name}")
print(f"描述: {description}")
print(f"奖励: {reward}")
# print(f"任务id: {apply_link.split('id=')[-1]}")
print("-" * 50)
task_list.update({task_name: apply_link.split('id=')[-1]})
if len(task_list) > 0:
print(f'获取到{len(task_list)}个可接任务')
for name, link_id in task_list.items():
print('*' * 30)
print(f'尝试领取任务:{name}')
response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=apply&id={link_id}')
if 'do=draw' in response.text:
response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={link_id}')
if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text:
print(f'任务:{name} 直接完成')
else:
print(f'任务:{name} 失败' + response.text)
elif '申请此任务需要先完成另一个任务' in response.text:
html_message = etree.HTML(response.text)
qianzhi_task = html_message.xpath('//div[@id="messagetext"]//p[@class="alert_btnleft"]/a/@href')[0].split("id=")[-1]
print(f'任务:{name} 领取失败 | 原因是前置任务未完成跳转前置任务id{qianzhi_task}')
self.task_view(qianzhi_task)
elif '任务申请成功' in response.text:
print(f'任务:{name} 领取成功')
elif '不是进行中的任务' in response.text:
print(f'任务:{name} 无法直接完成')
else:
print(f'任务:{name} 领取失败')
print(response.text)
time.sleep(1)
print('-' * 50)
else:
print('没有可接任务')
# Log(f'\n没有可接任务')
print('-' * 50)
except Exception as e:
print(f'检查任务信息失败:{e}')
def check_task_doing(self):
try:
response = self.session.get('https://bbs.3dmgame.com/home.php?mod=task&item=doing')
# print(response.text)
html = etree.HTML(response.text)
task_rows = html.xpath('//div[@class="ptm"]//table//tr')
task_list = []
for row in task_rows:
# 提取任务名称
task_name = row.xpath('.//td[2]//h3/a/text()')[0] if row.xpath('.//td[2]//h3/a/text()') else ""
# 提取任务ID
task_id = row.xpath('.//td[2]//h3/a/@href')[0].split('id=')[-1] if row.xpath('.//td[2]//h3/a/@href') else ""
# 提取do=view链接任务详情链接
# view_link = row.xpath('.//td[2]//h3/a[contains(@href, "do=view")]/@href')[0] if row.xpath('.//td[2]//h3/a[contains(@href, "do=view")]/@href') else ""
# 提取领取链接(do=draw类型)
# draw_links = row.xpath('.//td[4]/p/a[contains(@href, "do=draw")]/@href')[0] if row.xpath('.//td[4]/p/a/@href') else ""
print(f"进行中的任务: 《{task_name}")
task_list.append({task_name: task_id})
print('-' * 30)
if len(task_list) > 0:
return task_list
else:
print('没有进行中的任务')
# Log(f'\n没有进行中的任务')
return []
except Exception as e:
print(f'检查任务进行中失败:{e}')
def do_task(self, tk_list):
print(f'获取到{len(tk_list)}个待完成任务')
for task_name, task_id in tk_list.items():
print(f'尝试完成任务:《{task_name}')
response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=view&id={task_id}')
if 'static/image/task/reward.gif' in response.text:
response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}')
if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text:
print(f'任务:《{task_name}》 完成')
else:
print(f'任务:《{task_name}》 失败')
print(response.text)
elif '完成此任务所需条件' in response.text:
print(f'任务:《{task_name}》 无完成条件')
response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}')
if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text:
print(f'任务:《{task_name}》 完成')
else:
print(f'任务:《{task_name}》 失败')
print(response.text)
else:
print(f'任务:《{task_name}》 有完成条件')
tree = etree.HTML(response.text)
tables = tree.xpath("//table[@class='tfm']//td[@class='bbda']/a/@href")[0]
# print(tables)
reply_td = tree.xpath("//table[@class='tfm']//td[@class='bbda'][contains(., '')]/text()[normalize-space()]")[1]
reply_td = reply_td.replace(' ', '')
# print(reply_td)
reply_count = re.search(r'(\d+)次', reply_td).group(1) if re.search(r'(\d+)次', reply_td) else "未知"
if 'thread' in tables:
response = self.session.get(f'https://bbs.3dmgame.com/{tables}')
formhash = re.search(r'name="formhash" value="(\w+)"', response.text).group(1)
fid_match = re.search(r"fid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1)
tid_match = re.search(r"tid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1)
print('回复次数:' + reply_count)
if int(reply_count) > 5:
print('回复次数大于5次任务跳过')
else:
for _ in range(int(reply_count)):
for i in range(3):
result = self.reply(tid_match, fid_match, formhash)
if result:
break
time.sleep(10)
time.sleep(35)
print(f'已完成任务 《{task_name}》 回复指定文章要求')
else:
response = self.session.get(f'https://bbs.3dmgame.com/{tables}')
result = re.findall(r'mod=redirect&tid=(\d+)&goto', response.text)
if len(result) > 0:
response = self.session.get(f'https://bbs.3dmgame.com/thread-{random.choice(result)}-1-1.html')
formhash = re.search(r'name="formhash" value="(\w+)"', response.text).group(1)
fid_match = re.search(r"fid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1)
tid_match = re.search(r"tid\s*=\s*parseInt\('(\d+)'\)", response.text).group(1)
for _ in range(int(reply_count)):
for i in range(3):
result = self.reply(tid_match, fid_match, formhash)
if result:
break
time.sleep(10)
time.sleep(35)
print(f'已完成任务 《{task_name}》 回复指定主题要求')
response = self.session.get(f'https://bbs.3dmgame.com/home.php?mod=task&do=draw&id={task_id}')
if '恭喜您,任务已成功完成,您将收到奖励通知,请注意查收' in response.text:
print(f'任务:《{task_name}》 完成')
elif '您已完成该任务的' in response.text:
html = etree.HTML(response.text)
b = html.xpath('//div[@id="messagetext"]/p/text()')[0]
print(f'任务:《{task_name}》 失败:' + b.strip())
elif '您还没有开始执行任务,赶快哦' in response.text:
print(f'任务:《{task_name}》 失败:因任务特殊跳过该任务')
elif '您还没有开始执行任务' in response.text:
print(f'任务:《{task_name}》 失败:因任务特殊跳过该任务')
else:
print(f'任务:《{task_name}》 失败')
print(response.text)
time.sleep(3)
def reply(self, tid, fid, formhash):
response = requests.get("https://www.mxnzp.com/api/jokes/list?page=1&app_id=vqohyieoq7qklmgp&app_secret=FCc9Uf0h1c0LNkqeLRolebStTGfds3Fx")
response_json = response.json()
if response_json['code'] == 1 :
message = response_json['data']['list'][0]['content']
else:
message = '我是新玩家,搞不懂' + random.choice(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'])
data = {
'file': '',
'message': message,
'posttime': str(int(time.time())),
'formhash': formhash,
'usesig': '1',
'subject': ' ',
}
response = self.session.post(f'https://bbs.3dmgame.com/forum.php?mod=post&action=reply&fid={fid}&tid={tid}&extra=page%3D1&replysubmit=yes&infloat=yes&handlekey=fastpost&inajax=1', data=data)
if '回复发布成功' in response.text:
print('回帖成功,等待35秒后回复下个帖子')
return True
else:
print('回复失败,未知原因')
return False
def main(self):
self.user_info()
print('-' * 50)
print('开始做论坛任务-->>>>>>>>')
self.check_task()
task_list = self.check_task_doing()
if task_list:
for task in task_list:
self.do_task(task)
print('等待30秒进行下一个账号')
self.session.close()
print('*' * 50)
time.sleep(30)
Log('-' * 30)
if __name__ == '__main__':
try:
if 'bbs3dmck' in os.environ:
bbs3dmck = re.split("@|&", os.environ.get("bbs3dmck"))
print(f'查找到{len(bbs3dmck)}个账号\n')
else:
bbs3dmck = None
print('无bbs3dmck变量')
Log(f'\n未填入bbs3dmck变量')
if bbs3dmck:
z = 1
for ck in bbs3dmck:
print(f'登录第{z}个账号')
threeDM = ThreeDMGame(ck)
threeDM.main()
z+= 1
except Exception as e:
print(e)
try:
send_notification_message(title='3dmgame论坛签到') # 发送通知
except Exception as e:
print(e)

View File

@@ -0,0 +1,388 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/PPark.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/PPark.py
# Repo: lksky8/sign-ql
# Path: PPark.py
# UploadedAt: 2025-09-22T11:01:17Z
# SHA256: 120e73308bc1ccfb9db8ebd87357364850257a25ba1bc039d67c2967fe6c8e19
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
PP停车签到
作者https://github.com/lksky8/sign-ql
最后更新日期2025-9-22
食用方法变量输入export pp_token=账号1#token1&账号2#token2
支持多用户运行
多用户用&或者@隔开
例如账号113800000000#eyJhbGciOiJIUzI1NiJ9.eyj 账号2 139000000000#eyJhbGciOiJIUzI1NiJ9.eyj
则变量为
export pp_token="13800000000#eyJhbGciOiJIUzI1NiJ9.eyj&13900000000#eyJhbGciOiJIUzI1NiJ9.eyj"
每天运行两次否则token会过期
cron: 0 40 0,12 * * *
"""
import requests
import base64
from urllib.parse import quote
import json
import hashlib
import time
import os
import re
KEY_ENCRYPT = "2363ECDFC54A5AF12477D3D45333A19F" # key1 用于加密
KEY_DECRYPT = "466d67cf8f9810707404fae5ed172b8e" # key2 用于解密
WX_ENCRYPT = "riegh^ee:w0fok5je5eeS{eecaes1nep"
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'\n{cont}'
send_msg += f'\n{cont}'
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
api_headers = {
'Host': 'api.660pp.com',
'accept': '*/*',
'content-type': 'application/x-www-form-urlencoded',
'rest_api_type': '1',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Parking/4.3.2 (iOS 16.6.1; iPhone15,2; Build/1312) NetType/WIFI',
'accept-language': 'zh_CN',
}
wx_headers = {
'Host': 'user-api.4pyun.com',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf2541022) XWEB/16467',
'xweb_xhr': '1',
'content-type': 'application/x-www-form-urlencoded',
'accept': '*/*',
'sec-fetch-site': 'cross-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://servicewechat.com/wxa204074068ad40ef/879/page-frame.html',
'accept-language': 'zh-CN,zh;q=0.9',
'priority': 'u=1, i',
}
def transform(bytes_data: bytearray, key: str) -> bytearray:
len_key = len(key)
len_b = len(bytes_data)
for i in range(len_b):
index = (len_b - i) % len_key
key_byte = ord(key[index])
in_byte = bytes_data[i]
flipped = in_byte ^ 0xFF
bytes_data[i] = key_byte ^ flipped
return bytes_data
def encrypt(arg: str, key: str) -> str:
"""加密,对应提供的 encrypt 方法"""
bytes_data = bytearray(arg.encode('utf-8'))
transformed = transform(bytes_data, key)
return base64.b64encode(transformed).decode('utf-8')
def decrypt(arg: str) -> str:
"""解密,对应提供的 decrypt 方法"""
bytes_data = bytearray(base64.b64decode(arg))
transformed = transform(bytes_data, KEY_DECRYPT)
return transformed.decode('utf-8')
def save_or_update_phone_data(phone_key, new_data, file_path='PPark_data.json'):
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
existing_data = json.load(f)
else:
existing_data = {}
if phone_key in existing_data:
existing_data[phone_key].update(new_data) # 合并新旧数据
print(f"[{phone_key}] 数据已更新!")
else:
existing_data[phone_key] = new_data # 新增数据
print(f"[{phone_key}] 新增数据!")
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(existing_data, f, ensure_ascii=False, indent=4)
def get_user_ids_and_tokens(file_path='PPark_data.json'):
try:
with open(file_path, 'r', encoding='utf-8') as f:
phone_data = json.load(f)
results = []
for phone_key, data in phone_data.items():
token = data.get('refresh_token')
if token:
results.append({
'phone_key': phone_key,
'refresh_token': token,
'user_name': data.get('user_name'),
'user_id': data.get('user_id')
})
return results
except FileNotFoundError:
print(f"文件 {file_path} 不存在!")
return []
except json.JSONDecodeError:
print(f"文件 {file_path} 格式错误!")
return []
def get_userdata(u):
user_phone = u.split('#')[0]
user_token = u.split('#')[1]
try:
with open('PPark_data.json', 'r', encoding='utf-8') as f:
cache_data = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
cache_data = {}
if user_phone not in cache_data:
print(f'[{user_phone}] 不存在于缓存中,尝试初始化数据')
init_refresh_token(user_phone,user_token)
else:
print(f'[{user_phone}] 已存在于缓存中,直接读取数据')
refresh_token(user_phone,user_token,cache_data[user_phone]['refresh_token'])
old_user_token = cache_data[user_phone]['init_token']
if old_user_token != user_token:
print(f'[{user_phone}] token已更新尝试刷新')
init_refresh_token(user_phone,user_token)
def md5_encrypt(s: str):
return hashlib.md5(s.encode('utf-8')).hexdigest()
def get_user_info(phone: str, token: str):
headers = wx_headers.copy()
headers['authorization'] = f'Bearer {token}'
try:
response = requests.get('https://user-api.4pyun.com/rest/2.0/user/whoami',headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == '1001':
print(f"[{response_json['payload']['nickname']}] 获取用户信息:成功")
return response_json['payload']['nickname'], response_json['payload']['identity']
else:
print(f"[{phone}] 获取用户信息:失败:{response_json}")
return None
except requests.RequestException as e:
print(f"[{phone}] 获取用户信息_请求异常{e}")
except json.JSONDecodeError:
print(f"[{phone}] 获取用户信息_响应不是有效的JSON格式")
except Exception as e:
print(f"[{phone}] 获取用户信息_其他异常{e}")
def refresh_token(mobile: str, i_token: str, r_token: str):
headers = api_headers.copy()
headers['rest_api_token'] = r_token
try:
response = requests.put('https://api.660pp.com/rest/1.6/user/token', headers=headers)
response_json = response.json()
# print(response_json)
if response_json['code'] == '1001':
result = json.loads(decrypt(response_json['result']))
print(f"[{mobile}] 刷新token成功")
save_or_update_phone_data(mobile,{'init_token': i_token,'refresh_token': result['token']})
elif response_json['code'] == '401':
print(f"[{mobile}] 刷新token失败token已失效")
Log(f"[{mobile}] 刷新token失败token已失效")
else:
print(f"[{mobile}] 刷新token失败{response_json}")
except requests.RequestException as e:
print(f"[{mobile}] 刷新token_请求异常{e}")
except json.JSONDecodeError:
print(f"[{mobile}] 刷新token_响应不是有效的JSON格式")
except Exception as e:
print(f"[{mobile}] 刷新token_其他异常{e}")
def init_refresh_token(mobile: str, token: str):
headers = api_headers.copy()
headers['rest_api_token'] = token
try:
response = requests.put('https://api.660pp.com/rest/1.6/user/token', headers=headers)
response_json = response.json()
# print(response_json)
if response_json['code'] == '1001':
result = json.loads(decrypt(response_json['result']))
user_name, user_id = get_user_info(mobile, token)
save_or_update_phone_data(mobile,{'user_name': user_name, 'user_id': user_id, 'init_token': token, 'refresh_token': result['token']})
print(f"[{mobile}] 刷新token成功")
elif response_json['code'] == '401':
print(f"[{mobile}] 刷新token失败token已失效")
Log(f"[{mobile}] 刷新token失败token已失效")
else:
print(f"[{mobile}] 刷新token失败{response_json}")
except requests.RequestException as e:
print(f"[{mobile}] 刷新token_请求异常{e}")
except json.JSONDecodeError:
print(f"[{mobile}] 刷新token_响应不是有效的JSON格式")
except Exception as e:
print(f"[{mobile}] 刷新token_其他异常{e}")
def day_sign(nickname: str, token: str):
headers = api_headers.copy()
headers['rest_api_token'] = token
try:
response = requests.get('https://api.660pp.com/rest/1.6/reward/bonus?yc7OyqO6qQ%3D%3D=rL7JhL/NrriG2tPZ2aegog%3D%3D', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == '1001':
result = json.loads(decrypt(response_json['result']))
message = result['message'].replace('\r\n', '')
if '签到获得' in result['message'] or '已连续签到'in result['message']:
print(f"[{nickname}] 签到成功:{message} 已累计获得:{result['combo']} 积分")
Log(f"[{nickname}] 签到成功:{message} 已累计获得:{result['combo']} 积分")
elif message == '您已签到成功' :
print(f"[{nickname}] 签到失败:已签到")
Log(f"[{nickname}] 已签到")
else:
print(f"[{nickname}] 签到失败:{message}")
Log(f"[{nickname}] 签到失败:{message}")
else:
print(f"[{nickname}] 获取签到数据失败:{response_json}")
except requests.RequestException as e:
print(f"[{nickname}] 签到_请求异常{e}")
except json.JSONDecodeError:
print(f"[{nickname}] 签到_响应不是有效的JSON格式")
except Exception as e:
print(f"[{nickname}] 签到_其他异常{e}")
def get_task(nickname: str, token: str):
headers = wx_headers.copy()
headers['authorization'] = f'Bearer {token}'
try:
response = requests.get('https://user-api.4pyun.com/rest/2.0/bonus/reward/task/list?%2B9Hnx%2FPy=7bL7p%2FqgoK77uPOi%2B8WjqP%2Fw', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == '1001':
video_task = [task for task in response_json['payload']['row'] if task['name'] == '看视频得积分'][0]
referer_url = video_task['referer_url']
print(f'[{nickname}] 获取视频任务数据成功')
return referer_url.split('&voucher=')[1]
else:
print(f"[{nickname}] 获取任务_失败{response_json}")
Log(f"[{nickname}] 获取视频任务数据失败:{response_json}")
return None
except requests.RequestException as e:
print(f"[{nickname}] 获取任务_请求异常{e}")
except json.JSONDecodeError:
print(f"[{nickname}] 获取任务_响应不是有效的JSON格式")
except Exception as e:
print(f"[{nickname}] 获取任务_其他异常{e}")
def complete_task(nickname: str, token: str, task_id: str):
headers = wx_headers.copy()
headers['authorization'] = f'Bearer {token}'
headers['content-type'] = 'application/json;charset=utf-8'
try:
data = '{"app_id":"wxa204074068ad40ef","purpose":"reward:motivate:advertising","voucher":"voucher_data"}'.replace('voucher_data', task_id)
encrypt_data = encrypt(data,WX_ENCRYPT)
response = requests.post('https://user-api.4pyun.com/rest/2.0/bonus/reward/task/complete', headers=headers, data=encrypt_data)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == '1001':
print(f"[{nickname}] 看视频:任务完成")
headers['content-type'] = 'application/x-www-form-urlencoded'
response = requests.get('https://user-api.4pyun.com/rest/2.0/bonus/reward/acquire?%2B9Hnx%2FPy=7bL7p%2FqgoK77uPOi%2B8WjqP%2Fw&6u%2FT5%2Ffp8w%3D%3D=%2Fv%2Fp%2Fej%2BvsH17qPs9L7xqvir%2FqDo7sjk8fTx', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == '1001':
print(f"[{nickname}] 看视频:任务奖励已领取,{response_json['payload']['message']}")
Log(f"[{nickname}] 看视频:任务奖励已领取,{response_json['payload']['message']}")
elif response_json['message'] == '已达积分领取次数上限':
print(f"[{nickname}] 看视频:积分已领取")
else:
print(f"[{nickname}] 看视频:{response_json['message']}")
Log(f"[{nickname}] 看视频:{response_json['message']}")
else:
print(f"[{nickname}] 看视频任务失败:{response_json}")
Log(f"[{nickname}] 看视频任务失败:{response_json}")
except requests.RequestException as e:
print(f"[{nickname}] 看视频任务_请求异常{e}")
except json.JSONDecodeError:
print(f"[{nickname}] 看视频任务_响应不是有效的JSON格式")
except Exception as e:
print(f"[{nickname}] 看视频任务_其他异常{e}")
def reward_balance(nickname: str, token: str, user_id: str):
headers = wx_headers.copy()
headers['authorization'] = f'Bearer {token}'
try:
response = requests.get(f'https://user-api.4pyun.com/rest/2.0/reward/balance?rP7%2Fz%2BPx7u8%3D={quote(encrypt(user_id,WX_ENCRYPT))}&7%2BnE5cfz8g%3D%3D={quote(encrypt(user_id,WX_ENCRYPT))}&%2Fbb%2F6P7j4erz=pw%3D%3D', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == '1001':
print(f"[{nickname}] 积分余额:{response_json['payload']['balance']}")
Log(f"[{nickname}] 积分余额:{response_json['payload']['balance']}")
else:
print(f"[{nickname}] 获取积分余额_失败{response_json}")
Log(f"[{nickname}] 获取积分余额_失败{response_json}")
except requests.RequestException as e:
print(f"[{nickname}] 获取积分余额_请求异常{e}")
except json.JSONDecodeError:
print(f"[{nickname}] 获取积分余额_响应不是有效的JSON格式")
except Exception as e:
print(f"[{nickname}] 获取积分余额_其他异常{e}")
if __name__ == '__main__':
if 'pp_token' in os.environ:
pp_token = re.split("@|&", os.environ.get("pp_token"))
print(f'查找到{len(pp_token)}个账号')
else:
pp_token = []
print('请填入pp_token变量')
Log('请填入pp_token变量')
try:
if pp_token:
for pp_token_item in pp_token:
get_userdata(pp_token_item)
user_data = get_user_ids_and_tokens()
if user_data:
print(f"配置缓存中读取到{len(user_data)}个账号")
print('*' * 50)
z = 1
for item in user_data:
print('-' * 50)
print(f'登录第{z}个账号>>>>>>')
phone_key = item.get('phone_key')
new_token = item.get('refresh_token')
user_name = item.get('user_name')
user_id = item.get('user_id')
if new_token:
day_sign(user_name,new_token)
for _ in range(2):
voucher = get_task(user_name, new_token)
if voucher:
complete_task(user_name, new_token, voucher)
time.sleep(5)
reward_balance(user_name,new_token,user_id)
time.sleep(3)
Log('-'*30)
z += 1
else:
print("未读取到用户数据,程序退出")
exit(0)
except Exception as e:
print(f'程序异常:{e}')
try:
send_notification_message(title='PP停车') # 发送通知
except Exception as e:
print('推送失败:' + str(e))

View File

@@ -0,0 +1,341 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/invalid/tyqh.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/invalid/tyqh.py
# Repo: lksky8/sign-ql
# Path: invalid/tyqh.py
# UploadedAt: 2026-05-23T06:33:20Z
# SHA256: 4c779933563a21d73534721d588cf8fd5aa9e6d6ced3e3b3bb414c91fb576708
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
统一茄皇
作者https://github.com/lksky8/sign-ql
最后更新日期2025-12-11
食用方法抓包url https://api.zhumanito.cn/api/login 请求体json {"wid":"12345678910"}
支持多用户运行
多用户用&或者@隔开
例如账号112345678910 账号2 12345678911
则变量为
export tyqh="12345678910@12345678911"
cron: 11 11 * * *
"""
import requests
import os
import re
import time
# 推送开关True为开启False为关闭
sendnotify = True
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'\n{cont}'
send_msg += f'\n{cont}'
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
api_headers = {
'Host': 'api.zhumanito.cn',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf2541022) XWEB/16571',
'authorization': '',
'accept': '*/*',
'origin': 'https://h5.zhumanito.cn',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://h5.zhumanito.cn/',
'accept-language': 'zh-CN,zh;q=0.9',
'priority': 'u=1, i',
}
def login(wid):
headers = {
'Host': 'api.zhumanito.cn',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf2541022) XWEB/16571',
'content-type': 'application/json;charset=UTF-8',
'accept': '*/*',
'origin': 'https://h5.zhumanito.cn',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
'referer': 'https://h5.zhumanito.cn/',
'accept-language': 'zh-CN,zh;q=0.9',
'priority': 'u=1, i',
}
try:
response = requests.post('https://api.zhumanito.cn/api/login', headers=headers, json={'wid': wid})
response.raise_for_status()
response_json = response.json()
if response_json['code'] == 200 and response_json['msg'] == '成功':
print(f"登录成功用户ID: {wid},拥有番茄:{response_json['data']['user']['fruit_num']}")
Log(f"登录成功用户ID: {wid},拥有番茄:{response_json['data']['user']['fruit_num']}")
if '"seed_stage":0' in response.text:
print(f"未种植番茄")
Log(f"未种植番茄")
time.sleep(1)
seed_tomato(response_json['data']['token'])
return response_json['data']['token']
else:
print(f"用户ID: {wid} 登录失败: {response_json['msg']}")
Log(f"用户ID: {wid} 登录失败: {response_json['msg']}")
return None
except requests.RequestException as e:
print(f"获取用户数据网络请求失败: {e}")
except ValueError as e:
print(f"获取用户数据解析JSON响应失败: {e}")
except KeyError as e:
print(f"获取用户数据JSON响应中缺少键: {e}")
except Exception as e:
print(f"获取用户数据时发生未知错误: {e}")
def get_tomato(user_token):
headers = api_headers.copy()
headers['authorization'] = user_token
try:
response = requests.post('https://api.zhumanito.cn/api/harvest', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == 200 and response_json['msg'] == '成功':
print(f"番茄收获成功,获得番茄:{response_json['data']['fruit_up']}")
Log(f"番茄收获成功,获得番茄:{response_json['data']['fruit_up']}")
seed_tomato(user_token)
else:
print(f"收获番茄失败: {response_json['msg']}")
Log(f"收获番茄失败: {response_json['msg']}")
except requests.RequestException as e:
print(f"收获番茄网络请求失败: {e}")
except ValueError as e:
print(f"收获番茄解析JSON响应失败: {e}")
except KeyError as e:
print(f"收获番茄JSON响应中缺少键: {e}")
except Exception as e:
print(f"收获番茄时发生未知错误: {e}")
def seed_tomato(user_token):
headers = api_headers.copy()
headers['authorization'] = user_token
try:
response = requests.post('https://api.zhumanito.cn/api/seed', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == 200 and response_json['msg'] == '成功':
print(f"番茄种植成功")
Log(f"番茄种植成功")
else:
print(f"番茄种植失败: {response_json['msg']}")
Log(f"番茄种植失败: {response_json['msg']}")
except requests.RequestException as e:
print(f"番茄种植网络请求失败: {e}")
except ValueError as e:
print(f"番茄种植解析JSON响应失败: {e}")
except KeyError as e:
print(f"番茄种植JSON响应中缺少键: {e}")
except Exception as e:
print(f"番茄种植时发生未知错误: {e}")
def get_task(user_token):
headers = api_headers.copy()
headers['authorization'] = user_token
try:
response = requests.get('https://api.zhumanito.cn/api/task?', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == 200 and response_json['msg'] == '成功':
print(f"获取任务成功")
task_lists = []
for task_list in response_json['data']['task']:
task_name = task_list['content']
reward_water = task_list['water_num']
reward_sun = task_list['sun_num']
if task_list['status'] == 1:
print(f"任务: {task_name}, 奖励水: {reward_water}, 奖励阳光: {reward_sun} 已完成")
else:
print(f"任务: {task_name}, 奖励水: {reward_water}, 奖励阳光: {reward_sun} 未完成")
task_lists.append({
'task_id': task_list['id'],
'task_name': task_name,
})
return task_lists
else:
print(f"获取任务失败: {response_json['msg']}")
return None
except requests.RequestException as e:
print(f"获取任务数据网络请求失败: {e}")
except ValueError as e:
print(f"获取任务数据解析JSON响应失败: {e}")
except KeyError as e:
print(f"获取任务数据JSON响应中缺少键: {e}")
except Exception as e:
print(f"获取任务数据时发生未知错误: {e}")
def get_task_again(user_token):
headers = api_headers.copy()
headers['authorization'] = user_token
try:
response = requests.get('https://api.zhumanito.cn/api/task?', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == 200 and response_json['msg'] == '成功':
print(f"获取任务成功")
for task_list in response_json['data']['task']:
task_name = task_list['content']
reward_water = task_list['water_num']
reward_sun = task_list['sun_num']
if task_list['status'] == 1:
print(f"任务: {task_name}, 奖励水: {reward_water}, 奖励阳光: {reward_sun} 已完成")
Log(f"任务: {task_name}, 奖励水: {reward_water}, 奖励阳光: {reward_sun} 已完成")
else:
print(f"任务: {task_name}, 奖励水: {reward_water}, 奖励阳光: {reward_sun} 未完成")
Log(f"任务: {task_name}, 奖励水: {reward_water}, 奖励阳光: {reward_sun} 未完成")
else:
print(f"获取任务失败: {response_json['msg']}")
Log(f"获取任务失败: {response_json['msg']}")
return None
except requests.RequestException as e:
print(f"获取任务数据网络请求失败: {e}")
except ValueError as e:
print(f"获取任务数据解析JSON响应失败: {e}")
except KeyError as e:
print(f"获取任务数据JSON响应中缺少键: {e}")
except Exception as e:
print(f"获取任务数据时发生未知错误: {e}")
def task_complete(user_token, task_id,task_name):
headers = api_headers.copy()
headers['authorization'] = user_token
headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
try:
response = requests.post('https://api.zhumanito.cn/api/task/complete', headers=headers, data=f'task_id={task_id}&')
response.raise_for_status()
response_json = response.json()
if response_json['code'] == 200 and response_json['msg'] == '成功':
for task_status in response_json['data']['task']:
if task_status['task_id'] == task_id and task_status['status']:
print(f"任务: {task_name} 成功,剩余水: {response_json['data']['user']['water_num']}, 剩余阳光: {response_json['data']['user']['sun_num']}")
else:
print(f"任务: {task_name} 失败: {response_json['msg']}")
except requests.RequestException as e:
print(f"完成任务: {task_name} 时网络请求失败: {e}")
except ValueError as e:
print(f"完成任务: {task_name} 时解析JSON响应失败: {e}")
except KeyError as e:
print(f"完成任务: {task_name} 时JSON响应中缺少键: {e}")
except Exception as e:
print(f"完成任务: {task_name} 时发生未知错误: {e}")
def water(user_token):
headers = api_headers.copy()
headers['authorization'] = user_token
headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
try:
response = requests.post('https://api.zhumanito.cn/api/water', headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['code'] == 200 and response_json['msg'] == '成功':
print(f"浇水成功,剩余水: {response_json['data']['user']['water_num']}, 剩余阳光: {response_json['data']['user']['sun_num']}")
Log(f"浇水成功,剩余水: {response_json['data']['user']['water_num']}, 剩余阳光: {response_json['data']['user']['sun_num']}")
return True
elif response_json['code'] == 10006 and response_json['msg'] == '能量值不足了,可以坚持做任务获取哦~':
print("不够水了")
Log("不够水了")
return False
elif response_json['code'] == 10007 and response_json['msg'] == '今日浇水已达到上限,请明天再来哦~':
print("今日浇水次数已达到上限")
Log("今日浇水次数已达到上限")
return False
elif response_json['code'] == 10008 and response_json['msg'] == '已成熟,不必浇灌':
print("番茄已成熟,自动收获")
Log("番茄已成熟,自动收获")
get_tomato(user_token)
return True
else:
print(f"浇水失败: {response_json['msg']}")
return False
except requests.RequestException as e:
print(f"浇水时网络请求失败: {e}")
except ValueError as e:
print(f"浇水时解析JSON响应失败: {e}")
except KeyError as e:
print(f"浇水时JSON响应中缺少键: {e}")
except Exception as e:
print(f"浇水时发生未知错误: {e}")
finally:
time.sleep(3)
def view_page(wid):
headers = {
'Host': 'api.zhumanito.cn',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'sec-fetch-site': 'same-site',
'sec-fetch-dest': 'document',
'accept-language': 'zh-CN,zh-Hans;q=0.9',
'sec-fetch-mode': 'navigate',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.64(0x1800402b) NetType/WIFI Language/zh_CN miniProgram/wx532ecb3bdaaf92f9',
'referer': 'https://h5.zhumanito.cn/',
}
requests.get(f'https://api.zhumanito.cn/?wid={wid}', headers=headers)
if __name__ == '__main__':
if 'tyqh' in os.environ:
tyqh_session = re.split("@|&", os.environ.get("tyqh"))
print(f'查找到{len(tyqh_session)}个账号')
else:
tyqh_session = []
if tyqh_session:
z = 1
for wid in tyqh_session:
print('*'*50)
print(f'开始处理第{z}个账号')
Log(f'处理第{z}个账号:')
print('-' * 30)
token = login(wid)
print('-' * 30)
all_task = get_task(token)
print('-'*30)
print('开始做任务')
for task in all_task:
if task['task_name'] == '浏览指定页面':
view_page(wid)
print('任务: 浏览指定页面 成功')
time.sleep(3)
continue
task_complete(token, task['task_id'], task['task_name'])
time.sleep(3)
print('-' * 30)
while water(token):
pass
get_task_again(token)
Log('\n')
z += 1
time.sleep(10)
else:
print('请填入tyqh变量')
Log('请填入tyqh变量')
if sendnotify:
try:
send_notification_message(title='统一茄皇') # 发送通知
except Exception as e:
print('推送失败:' + str(e))

View File

@@ -0,0 +1,584 @@
// # Source: https://github.com/DearSong15/ql-scripts/blob/main/zsp_video.js
// # Raw: https://raw.githubusercontent.com/DearSong15/ql-scripts/main/zsp_video.js
// # Repo: DearSong15/ql-scripts
// # Path: zsp_video.js
// # UploadedAt: 2026-05-11T15:03:30Z
// # SHA256: 960b2e28799c40a00eb4bd75dcda1e61b3ab747374716073995c75053c3083ee
// # Category: web版/账密
// # Evidence: web/H5关键词 + username/password/login
//
//走个码吧,谢谢兄弟们了
//后台注册地址https://zsp.99panel.top/#/register?inviteCode=lzwbaleD
//前台https://a.zsp55.app/
//变量格式:备注#SecretId#SecretKey#deviceld
const ENV_NAME = "中视频";
const USER_AGENT = "Mozilla/5.0 (Linux; Android 15; 23013RK75C Build/AQ3A.250226.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.260 Mobile Safari/537.36 (Immersed/39.42857) Html5Plus/1.0";
const BASE_URL = "https://x1.zsptv.online";
// 工具函数
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// HTTP请求函数
async function httpRequest(options) {
return new Promise((resolve, reject) => {
const url = new URL(options.url);
const https = url.protocol === 'https:' ? require('https') : require('http');
const req = https.request({
hostname: url.hostname,
port: url.port || (url.protocol === 'https:' ? 443 : 80),
path: url.pathname + url.search,
method: options.method || 'GET',
headers: options.headers || {}
}, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
// 调试:记录响应
if (res.statusCode === 403) {
console.log(`🔍 响应体: ${data.substring(0, 200)}...`);
}
resolve({
statusCode: res.statusCode,
headers: res.headers,
body: data
});
});
});
req.on('error', (err) => {
reject(err);
});
if (options.body) {
req.write(options.body);
}
req.end();
});
}
// Unicode解码函数
function decodeUnicode(str) {
if (!str) return '';
return str.replace(/\\u[\dA-F]{4}/gi,
match => String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16)));
}
// 主函数
async function main() {
console.log(`🔔 脚本开始运行,时间: ${new Date().toLocaleString()}\n`);
// 读取环境变量
const accounts = loadAccounts();
if (accounts.length === 0) {
console.log("❌ 未找到有效的账号配置,请检查环境变量格式!");
return;
}
console.log(`✅ 找到 ${accounts.length} 个账号\n`);
// 遍历所有账号
for (let i = 0; i < accounts.length; i++) {
const account = accounts[i];
console.log(`\n📱 开始处理账号 ${i+1}: ${account.remark}`);
console.log("=".repeat(30));
try {
await processAccount(account);
} catch (error) {
console.log(`❌ 处理账号 ${account.remark} 时出错: ${error.message}`);
}
// 账号间延迟
if (i < accounts.length - 1) {
console.log("\n⏳ 等待5秒后处理下一个账号...");
await wait(5000);
}
}
console.log(`\n🎉 所有账号处理完成!`);
}
// 加载账号信息
function loadAccounts() {
const accounts = [];
// 尝试从不同环境变量名称读取
const envNames = ['ZSP', 'AD_WATCH_ACCOUNTS'];
let envValue = '';
for (const envName of envNames) {
if (process.env[envName]) {
envValue = process.env[envName];
console.log(`📋 从环境变量 ${envName} 读取配置`);
break;
}
}
if (!envValue) {
console.log("⚠️ 请设置环境变量 ZSP 或 AD_WATCH_ACCOUNTS");
return accounts;
}
const accountStrs = envValue.split("\n").filter(str => str.trim());
for (const str of accountStrs) {
const parts = str.split("#");
if (parts.length >= 4) {
accounts.push({
remark: parts[0] || "未命名账号",
secretId: parts[1],
secretKey: parts[2],
deviceId: parts[3]
});
console.log(`✅ 加载账号: ${parts[0] || "未命名账号"}`);
} else {
console.log(`⚠️ 忽略格式错误的环境变量: ${str}`);
}
}
return accounts;
}
// 处理单个账号
async function processAccount(account) {
// 1. 登录获取token
const token = await login(account);
if (!token) {
console.log("❌ 登录失败,跳过此账号");
return;
}
console.log(`✅ 登录成功token获取完成`);
// 2. 检测并执行签到
const signed = await checkAndSign(token, account);
if (!signed) {
console.log("❌ 签到失败,跳过广告任务");
return;
}
console.log(`\n📺 开始执行广告观看任务`);
console.log("-".repeat(30));
let successCount = 0;
let failCount = 0;
let totalReward = 0;
let consecutiveErrors = 0;
const maxAds = 50; // 最多执行50次广告任务
for (let adCount = 0; adCount < maxAds; adCount++) {
console.log(`\n🔄 第 ${adCount + 1}/${maxAds} 次广告任务`);
// 如果连续出现3次错误重新登录获取新token
if (consecutiveErrors >= 3) {
console.log("⚠️ 连续3次错误尝试重新登录...");
const newToken = await login(account);
if (newToken) {
token = newToken;
console.log("✅ 重新登录成功,继续任务");
consecutiveErrors = 0;
} else {
console.log("❌ 重新登录失败,跳过此账号");
break;
}
}
try {
// 获取广告信息
const adInfo = await getNextAd(token, account);
if (!adInfo) {
console.log(` ⚠️ 获取广告失败`);
failCount++;
consecutiveErrors++;
await wait(3000);
continue;
}
console.log(` 📱 广告标题: ${adInfo.title}`);
console.log(` ⏱️ 需要观看: ${adInfo.duration}`);
console.log(` 🪙 预期奖励: ${adInfo.reward || 0}`);
// 开始播放广告
console.log(` ▶️ 开始播放广告...`);
const playResult = await claimReward(token, account, adInfo.id, adInfo.duration);
if (playResult && playResult.success) {
console.log(` ✅ 广告观看成功!`);
console.log(` 💰 获得奖励: ${playResult.reward || 0}`);
successCount++;
totalReward += parseInt(playResult.reward) || 0;
consecutiveErrors = 0; // 重置错误计数
// 任务间延迟 (避免请求过快)
if (adCount < maxAds - 1) {
const randomDelay = Math.floor(Math.random() * 3000) + 3000; // 3-6秒随机延迟
console.log(` ⏳ 等待${Math.round(randomDelay/1000)}秒后处理下一个广告...`);
await wait(randomDelay);
}
} else {
console.log(` ❌ 广告观看失败`);
failCount++;
consecutiveErrors++;
await wait(3000);
}
} catch (error) {
console.log(` ❌ 广告任务出错: ${error.message}`);
failCount++;
consecutiveErrors++;
await wait(3000);
}
}
console.log("\n" + "=".repeat(30));
console.log(`📊 任务完成统计:`);
console.log(` ✅ 成功: ${successCount}`);
console.log(` ❌ 失败: ${failCount}`);
console.log(` 💰 总计奖励: ${totalReward}`);
console.log(` 📈 成功率: ${((successCount/maxAds)*100).toFixed(1)}%`);
}
// 登录接口
async function login(account) {
const url = `${BASE_URL}/api/app/v1/auth/secretKeyLogin`;
const body = {
secretId: account.secretId,
secretKey: account.secretKey
};
const headers = {
"Accept": "*/*",
"User-Agent": USER_AGENT,
"app-device": JSON.stringify({
"id": account.deviceId,
"brand": "xiaomi",
"model": "23013RK75C",
"platform": "android",
"system": "Android 15"
}),
"Content-Type": "application/json",
"Host": "x1.zsptv.online"
};
try {
const response = await httpRequest({
url: url,
method: "POST",
headers: headers,
body: JSON.stringify(body)
});
if (response.statusCode !== 200) {
console.log(`❌ 登录请求失败,状态码: ${response.statusCode}`);
return null;
}
const data = JSON.parse(response.body);
if (data.code === 0 && data.data && data.data.token) {
return data.data.token;
} else {
console.log(`❌ 登录失败: ${data.message || "未知错误"}`);
return null;
}
} catch (error) {
console.log(`❌ 登录请求失败: ${error.message}`);
return null;
}
}
// 检测并执行签到
async function checkAndSign(token, account) {
const url = `${BASE_URL}/api/app/v1/device/userSign`;
const headers = {
"Accept": "*/*",
"User-Agent": USER_AGENT,
"Authorization": `Bearer ${token}`,
"app-device": JSON.stringify({
"id": account.deviceId,
"brand": "xiaomi",
"model": "23013RK75C",
"platform": "android",
"system": "Android 15"
}),
"Content-Type": "application/json",
"Host": "x1.zsptv.online"
};
try {
const response = await httpRequest({
url: url,
method: "POST",
headers: headers,
body: "{}"
});
if (response.statusCode !== 200) {
console.log(`❌ 签到请求失败,状态码: ${response.statusCode}`);
return false;
}
const data = JSON.parse(response.body);
if (data.code === 0) {
const message = decodeUnicode(data.message);
console.log(`✅ 签到结果: ${message}`);
if (data.data) {
console.log(` 🪙 获得签到金币: ${data.data.qiandao_money || 0}`);
console.log(` 📅 连续签到天数: ${data.data.continuousDays || 1}`);
}
return true;
} else {
const errorMsg = decodeUnicode(data.message || "未知错误");
console.log(`❌ 签到失败: ${errorMsg}`);
// 如果已签到也返回true继续执行广告任务
if (errorMsg && errorMsg.includes("已签到")) {
console.log(` 今日已签到,继续执行广告任务`);
return true;
}
return false;
}
} catch (error) {
console.log(`❌ 签到请求失败: ${error.message}`);
return false;
}
}
// 获取下一个广告
async function getNextAd(token, account) {
const url = `${BASE_URL}/api/app/v1/ad/next`;
const headers = {
"Accept": "*/*",
"User-Agent": USER_AGENT,
"Authorization": `Bearer ${token}`,
"app-device": JSON.stringify({
"id": account.deviceId,
"brand": "xiaomi",
"model": "23013RK75C",
"platform": "android",
"system": "Android 15"
}),
"Content-Type": "application/json",
"Host": "x1.zsptv.online"
};
try {
const response = await httpRequest({
url: url,
method: "GET",
headers: headers
});
if (response.statusCode !== 200) {
console.log(` ❌ 获取广告失败,状态码: ${response.statusCode}`);
if (response.body) {
const errorData = JSON.parse(response.body);
console.log(` 🔍 错误信息: ${errorData.message || "未知错误"}`);
}
return null;
}
const data = JSON.parse(response.body);
if (data.code === 0 && data.data && data.data.result) {
const ad = data.data.result;
return {
id: ad.id,
title: decodeUnicode(ad.title),
description: decodeUnicode(ad.description),
duration: parseInt(ad.video?.duration || 30), // 默认30秒
videoUrl: ad.video?.url || "",
playUrl: ad.video?.play_url || "",
reward: ad.reward
};
} else {
const errorMsg = decodeUnicode(data.message || "未知错误");
console.log(` ❌ 获取广告失败: ${errorMsg}`);
return null;
}
} catch (error) {
console.log(` ❌ 获取广告请求失败: ${error.message}`);
return null;
}
}
// 观看广告并获取奖励(整合播放和结束确认)
async function claimReward(token, account, adId, duration) {
const startTime = new Date().toISOString();
// 1. 开始播放广告
console.log(` 📅 播放开始时间: ${startTime}`);
const playResult = await startVideoPlay(token, account, adId, startTime);
if (!playResult || !playResult.playRecordId) {
console.log(` ❌ 广告播放开始失败`);
return { success: false };
}
console.log(` ✅ 播放开始成功! 记录ID: ${playResult.playRecordId}`);
console.log(` 💰 初始奖励: ${playResult.initialReward || 0}`);
// 2. 等待广告播放时间
const waitTime = duration * 1000;
console.log(` ⌛ 广告播放中,等待 ${duration} 秒...`);
await wait(waitTime);
// 3. 广告播放结束确认
console.log(` ⏹️ 广告播放完成,确认结束...`);
const endResult = await endVideoPlay(token, account, playResult.playRecordId);
if (endResult.success) {
console.log(` 🎉 广告观看完整流程完成!`);
return {
success: true,
reward: playResult.reward || 0,
playRecordId: playResult.playRecordId
};
} else {
console.log(` ⚠️ 广告观看完成,但结束确认失败`);
// 即使结束确认失败,也视为成功(因为已经播放完成)
return {
success: true,
reward: playResult.reward || 0,
playRecordId: playResult.playRecordId
};
}
}
// 开始播放广告
async function startVideoPlay(token, account, adId, playTime) {
const url = `${BASE_URL}/api/app/v1/ad/video/play`;
const body = {
clientIp: "",
deviceInfo: {
deviceId: account.deviceId,
platform: "android"
},
id: adId.toString(),
playTime: playTime
};
const headers = {
"Accept": "*/*",
"User-Agent": USER_AGENT,
"Authorization": `Bearer ${token}`,
"app-device": JSON.stringify({
"id": account.deviceId,
"brand": "xiaomi",
"model": "23013RK75C",
"platform": "android",
"system": "Android 15"
}),
"Content-Type": "application/json",
"Host": "x1.zsptv.online"
};
try {
const response = await httpRequest({
url: url,
method: "POST",
headers: headers,
body: JSON.stringify(body)
});
if (response.statusCode !== 200) {
console.log(` ❌ 开始播放广告失败,状态码: ${response.statusCode}`);
return null;
}
const data = JSON.parse(response.body);
if (data.code === 0 && data.data) {
return {
playRecordId: data.data.id,
initialReward: data.data.reward || 0,
reward: data.data.reward || 0
};
} else {
console.log(` ❌ 开始播放广告失败: ${data.message || "未知错误"}`);
return null;
}
} catch (error) {
console.log(` ❌ 开始播放广告请求失败: ${error.message}`);
return null;
}
}
// 结束广告播放
async function endVideoPlay(token, account, playRecordId) {
const url = `${BASE_URL}/api/app/v1/ad/video/ended`;
const endTime = new Date().toISOString();
const body = {
clientIp: "",
deviceInfo: {
deviceId: account.deviceId,
platform: "android"
},
id: playRecordId.toString(),
playTime: endTime
};
const headers = {
"Accept": "*/*",
"User-Agent": USER_AGENT,
"Authorization": `Bearer ${token}`,
"app-device": JSON.stringify({
"id": account.deviceId,
"brand": "xiaomi",
"model": "23013RK75C",
"platform": "android",
"system": "Android 15"
}),
"Content-Type": "application/json",
"Host": "x1.zsptv.online"
};
try {
const response = await httpRequest({
url: url,
method: "POST",
headers: headers,
body: JSON.stringify(body)
});
if (response.statusCode !== 200) {
console.log(` ⚠️ 广告结束确认失败,状态码: ${response.statusCode}`);
// 即使结束确认失败也返回成功避免403错误导致任务中断
return { success: true };
}
const data = JSON.parse(response.body);
if (data.code === 0) {
return { success: true };
} else {
console.log(` ⚠️ 广告结束确认返回异常: ${data.message || "未知错误"}`);
return { success: false };
}
} catch (error) {
console.log(` ⚠️ 广告结束确认请求失败: ${error.message}`);
return { success: false };
}
}
// 执行主函数
if (require.main === module) {
main().catch(console.error);
}

View File

@@ -0,0 +1,586 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/yxw_appsign.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_appsign.py
# Repo: lksky8/sign-ql
# Path: yxw_appsign.py
# UploadedAt: 2025-09-28T06:42:50Z
# SHA256: c6d91db16e3a84bf5dfc1e2c7d6cb38fb3f6d38f5829d7f496ba308fa7a77a10
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
'''
作者https://github.com/lksky8/sign-ql/
日期2025-9-28
网站游侠网APP签到
功能:签到、抽奖,金币可换现金买游戏,配合金币脚本使用可获得更多金币
变量yxwlogin='账号&密码' 多个账号用@或者#分割
定时:一天一次
cron45 8 * * *
'''
from json import JSONDecodeError
import requests
import hashlib
import time
import json
import os
import re
import datetime
if 'yxwlogin' in os.environ:
yxwlogin = re.split("@|#",os.environ.get("yxwlogin"))
print(f'查找到{len(yxwlogin)}个账号')
else:
yxwlogin = []
send_msg = ''
one_msg = ''
def log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'\n{cont}'
send_msg += f'\n{cont}'
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
api_headers = {
'Host': 'api3.ali213.net',
'accept': '*/*',
'user-agent': 'ali213app',
'accept-language': 'zh-Hans-CN;q=1',
}
def get_user_ids_and_tokens(file_path='youxia_data.json'):
try:
# 1. 读取JSON文件
with open(file_path, 'r', encoding='utf-8') as f:
phone_data = json.load(f)
# 2. 遍历每个手机号
results = []
for phone_key, data in phone_data.items():
user_name = data.get('nickname')
user_token = data.get('token')
if user_name and user_token: # 确保userId和token存在
results.append({
'phone_key': phone_key,
'user_name': user_name,
'token': user_token
})
# print(f"手机号: {phone_key}, userId: {user_id}, token: {token}")
return results
except FileNotFoundError:
print(f"文件 {file_path} 不存在!")
return []
except json.JSONDecodeError:
print(f"文件 {file_path} 格式错误!")
return []
def save_or_update_phone_data(phone_key, new_data, file_path='youxia_data.json'):
if os.path.exists(file_path):
with open(file_path, 'r', encoding='utf-8') as f:
existing_data = json.load(f)
else:
existing_data = {}
if phone_key in existing_data:
existing_data[phone_key].update(new_data) # 合并新旧数据
print(f"账号 [{phone_key}] 数据已更新!")
else:
existing_data[phone_key] = new_data # 新增数据
print(f"账号 [{phone_key}] 新增数据!")
with open(file_path, 'w', encoding='utf-8') as f:
json.dump(existing_data, f, ensure_ascii=False, indent=4)
def get_userdata(u):
phone_user = u.split('&')[0]
phone_password = u.split('&')[1]
try:
with open('youxia_data.json', 'r', encoding='utf-8') as f:
cache_data = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
cache_data = {}
if phone_user not in cache_data:
print(f'账号 {phone_user} 不存在于缓存中,尝试初始化数据')
login(phone_user, phone_password)
else:
print(f'账号 {phone_user} 已存在于缓存中,直接读取数据')
def md5_encode(string):
md5 = hashlib.md5()
md5.update(string.encode('utf-8'))
return md5.hexdigest()
def check_token(phone,token): # 检查token是否有效并返回新的token
try:
response = requests.get(f'https://api3.ali213.net/feedearn/checktoken?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1:
print(f'账号 [{phone}] token 有效')
save_or_update_phone_data(phone, {'token': response_json['token']})
return response_json['token']
else:
print(f'账号 [{phone}] token 无效')
log(f'账号 [{phone}] token 无效\n')
return None
except JSONDecodeError as e:
print(f'账号 [{phone}] 检查token失败: {e}')
except Exception as e:
print(f'账号 [{phone}] 检查token失败: {e}')
def token_exchanger(token):
headers = {
'Host': 'api3.ali213.net',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'sec-fetch-site': 'none',
'sec-fetch-mode': 'navigate',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 ali213app',
'accept-language': 'zh-CN,zh-Hans;q=0.9',
'sec-fetch-dest': 'document',
}
response = requests.get('https://api3.ali213.net/feedearn/tokenexchanger?token='+token+'&redirectUrl=https://api3.ali213.net/feedearn/luckybox',headers=headers)
print(response.text)
def userinfo(phone,token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/userbaseinfo?token={token}', headers=api_headers)
response_json = response.json()
if '"status":0' in response.text:
print(f'账号 [{phone}] 登录过期,需要重新登录')
log(f'账号 [{phone}] 登录过期,需要重新登录\n')
else:
experience = response_json['experience']
nextgrade_experience = response_json['nextgrade']['experience']
nextgrade_experience_coin = response_json['nextgrade']['coin']
money = response_json['money'] / 100
# 计算百分比
percent = (experience / nextgrade_experience) * 100
print(f'账号 [{response_json["nickname"]}] Lv.{response_json["grade"]} 目前金币:{response_json["coins"]} 现金:{money} 剩余{percent:.2f}% 即可升级获得{nextgrade_experience_coin}金币')
log(f'账号 [{response_json["nickname"]}] Lv.{response_json["grade"]} 目前金币:{response_json["coins"]} 现金:{money} 剩余{percent:.2f}% 即可升级获得{nextgrade_experience_coin}金币\n')
except requests.exceptions.RequestException as e:
print(f'账号 [{phone}] 获取用户信息失败: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{phone}] 获取用户信息失败: {e}')
except Exception as e:
print(f'账号 [{phone}] 获取用户信息失败: {e}')
def check_sign(name,token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/signing?action=set&token={token}', headers=api_headers)
if r'\u7528\u6237\u672a\u767b\u5f55\u6216\u767b\u5f55\u5df2\u8d85\u65f6' in response.text:
print(f'账号 [{name}] 登录过期,需要重新登录')
else:
response_json = response.json()
if response_json['data']['status'] == 1:
print(f'账号 [{name}] {response_json["data"]["msg"]},获得金币:{response_json["data"]["coins"]}')
log(f'账号 [{name}] {response_json["data"]["msg"]},获得金币:{response_json["data"]["coins"]}\n')
elif response_json['data']['status'] == 0:
print(f'账号 [{name}] {response_json["data"]["msg"]}')
log(f'账号 [{name}] {response_json["data"]["msg"]}\n')
else:
print(f'账号 [{name}] 签到失败:{response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 签到失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 签到失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 签到失败[其他]: {e}')
def login(phone, password):
headers = {
'Host': 'i.ali213.net',
'accept': '*/*',
'user-agent': 'ali213app',
'accept-language': 'zh-Hans-CN;q=1',
}
time10 = str(int(time.time()))
params = {
'action': 'login',
'from': 'feedearn',
'passwd': password,
'signature': md5_encode(f'username-{phone}-time-{time10}-passwd-{password}-from-feedearn-action-loginBGg)K6ng4?&x9sCIuO%C2%' + '{@TJ?fnFJ,bZKy/[/EWnw9UsC$@1'),
'time': time10,
'username': phone,
}
try:
response = requests.get('https://i.ali213.net/api.html', params=params, headers=headers)
response.raise_for_status()
response_json = response.json()
if response_json['status'] == 1 and response_json['msg'] == '登录成功':
print('登录成功: ' + response_json['data']['userinfo']['nickname'])
log(f'账号 [{response_json["data"]["userinfo"]["nickname"]}] 登录成功\n')
new_data = {
'uid': response_json['data']['userinfo']['uid'],
'nickname': response_json['data']['userinfo']['nickname'],
'token': response_json['data']['token'],
}
save_or_update_phone_data(phone, new_data)
elif response_json['status'] == 0:
print('登录失败: ' + response_json['msg'])
log(f'登录失败: {response_json["msg"]}\n')
else:
print('登录失败: ' + response_json)
except requests.exceptions.RequestException as e:
print(e)
def newusercheck(name, token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/newusercheck?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1 and response_json['msg'] == '您是老用户,所以还是跳老活动页面吧' or response_json['msg'] == '您参与完新用户活动了,现在去老活动页面吧':
# print(f'账号 [{name}] 老用户了,去周签')
olduser_sign(name, token)
elif response_json['status'] == 3 and response_json['msg'] == '您是最新用户,可以跳最新活动页面了':
# print(f'账号 [{name}] 新用户,去首月福利签到')
newuser_sign(name, token)
else:
print(f'账号 [{name}] 未知状态: {response_json}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 检查新用户失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 检查新用户失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 检查新用户失败[其他]: {e}')
def newuser_sign(name, token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/newuseractivitysign?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1:
print(f'账号 [{name}] 新用户福利: {response_json["msg"]}')
log(f'账号 [{name}] 新用户福利: {response_json["msg"]}\n')
newuser_monthsigncheck(name, token)
elif response_json['status'] == 0:
print(f'账号 [{name}] 新用户福利: {response_json["msg"]}')
log(f'账号 [{name}] 新用户福利: {response_json["msg"]}\n')
newuser_monthsigncheck(name, token)
else:
print(f'账号 [{name}] 新用户福利:签到失败 {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 新用户福利签到失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 新用户福利签到失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 新用户福利签到失败[其他]: {e}')
def newuser_monthsigncheck(name, token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/newusermonthactivity?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1:
prize = response_json['data']['prize']
today = datetime.datetime.now().strftime('%Y-%m-%d')
for item in prize:
if item['date'] == today:
print(f"账号 [{name}] 【新用户首月福利】 今天({today})的签到信息:")
log(f'账号 [{name}] 【新用户首月福利】 今天({today})的签到信息:\n')
newuser_kjl(name, token, item['con'], item['tit'], item['typeid'])
break
else:
print('没有获取到当天签到数据')
log('没有获取到当天签到数据\n')
month_day = response_json["data"]["qztime"].split(',')
print(f'账号 [{name}] 【新用户首月福利】已签到: {response_json["data"]["wcday"]}天,已领取{response_json["data"]["totalcoin"]}金币')
log(f'账号 [{name}] 【新用户首月福利】已签到: {response_json["data"]["wcday"]}天,已领取{response_json["data"]["totalcoin"]}金币\n')
print(f'账号 [{name}] 【新用户首月福利】从{month_day[0]}开始,到{month_day[1]}结束。记得绑定Steam账号才能领取奖励')
elif response_json['status'] == 0:
print(f'账号 [{name}] 新用户月签查询失败: {response_json["msg"]}')
log(f'账号 [{name}] 新用户月签查询失败: {response_json["msg"]}\n')
else:
print(f'账号 [{name}] 新用户月签查询失败: {response.text}')
log(f'账号 [{name}] 新用户月签查询失败: {response.text}\n')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 新用户月签查询失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 新用户月签查询失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 新用户月签查询失败[其他]: {e}')
def olduser_sign(name, token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/olduseractivitysign?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1:
print(f'账号 [{name}] 老用户福利: {response_json["msg"]}')
log(f'账号 [{name}] 老用户福利: {response_json["msg"]}\n')
olduser_weeksigncheck(name, user_token)
elif response_json['status'] == 0:
print(f'账号 [{name}] 老用户福利: {response_json["msg"]}')
log(f'账号 [{name}] 老用户福利: {response_json["msg"]}\n')
olduser_weeksigncheck(name, user_token)
else:
print(f'账号 [{name}] 老用户福利:签到失败 {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 老用户福利签到失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 老用户福利签到失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 老用户福利签到失败[其他]: {e}')
def olduser_weeksigncheck(name, token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/oldusermonthactivity?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1:
print(f'账号 [{name}] 【第{response_json["data"]["prizingno"]}阶段】已达成连续签到: {response_json["data"]["signday"]}')
log(f'账号 [{name}] 【第{response_json["data"]["prizingno"]}阶段】已达成连续签到: {response_json["data"]["signday"]}\n')
if response_json["data"]["signday"] == 7:
print(f'账号 [{name}] 第七天了,可领取奖励')
time.sleep(5)
kjl(name, token)
elif response_json['status'] == 0:
print(f'账号 [{name}] 周签查询失败: {response_json["msg"]}')
log(f'账号 [{name}] 周签查询失败: {response_json["msg"]}\n')
else:
print(f'账号 [{name}] 周签查询失败: {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 周签查询失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 周签查询失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 周签查询失败[其他]: {e}')
def kjl(name, token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/olduseractivityprizing?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1 and response_json['msg'] == '恭喜中奖':
print(f'账号 [{name}] 已领取奖励: 《{response_json["data"]["name"]}')
log(f'账号 [{name}] 已领取奖励: 《{response_json["data"]["name"]}\n')
elif response_json['status'] == 0:
print(f'账号 [{name}] 领取奖励失败: {response_json["msg"]}')
log(f'账号 [{name}] 领取奖励失败: {response_json["msg"]}\n')
else:
print(f'账号 [{name}] 领取奖励失败: {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 领取奖励失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 领取奖励失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 领取奖励失败[其他]: {e}')
def newuser_kjl(name,token,coin,mem,typeid):
try:
params = {
"coin": coin,
"mem": mem,
"token": token,
"typeid": str(typeid)
}
response = requests.post("https://api3.ali213.net/feedearn/newuserprizing", params=params, headers=api_headers)
response_json = response.json()
if response_json['status'] == 1 and response_json['msg'] == '成功':
print(f'账号 [{name}] 【新用户首月福利】已领取奖励: {coin}')
log(f'账号 [{name}] 【新用户首月福利】已领取奖励: {coin}\n')
elif response_json['status'] == 0:
print(f'账号 [{name}] 【新用户首月福利】领取奖励失败: {response_json["msg"]}')
log(f'账号 [{name}] 【新用户首月福利】领取奖励失败: {response_json["msg"]}\n')
else:
print(f'账号 [{name}] 【新用户首月福利】领取奖励失败: {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 【新用户首月福利】领取奖励失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 【新用户首月福利】领取奖励失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 【新用户首月福利】领取奖励失败[其他]: {e}')
def luckbox_cookies(phone, token):
headers = {
'Host': 'api3.ali213.net',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'sec-fetch-site': 'none',
'sec-fetch-mode': 'navigate',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 ali213app',
'accept-language': 'zh-CN,zh-Hans;q=0.9',
'sec-fetch-dest': 'document',
}
try:
response = requests.get(f'https://api3.ali213.net/feedearn/tokenexchanger?token={token}&redirectUrl=https://api3.ali213.net/feedearn/luckybox', headers=headers)
api3AliSSO = response.cookies.get_dict()
if api3AliSSO:
print(f'账号 [{phone}] 获取神秘宝箱cookies成功')
save_or_update_phone_data(phone, api3AliSSO)
else:
print(f'账号 [{phone}] 获取神秘宝箱cookies失败')
log(f'账号 [{phone}] 获取神秘宝箱cookies失败\n')
except requests.exceptions.RequestException as e:
print(f'账号 [{phone}] 获取神秘宝箱cookies失败[请求]: {e}')
except Exception as e:
print(f'账号 [{phone}] 获取神秘宝箱cookies失败[其他]: {e}')
def usermission(name,token):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/usermission?token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1:
print(f'账号 [{name}] 任务查询成功')
common_mission = response_json['data']['common']
if common_mission:
for mission in common_mission:
mission_name = mission['title']
mission_experience = mission['experience']
mission_total = mission['total']
mission_prize = mission['prize']
print(f'任务名称: {mission_name}, 每日次数: {mission_total}, 奖励经验: {mission_experience}, {mission_prize}')
elif response_json['status'] == 0:
print(f'账号 [{name}] 任务查询失败: {response_json["msg"]}')
else:
print(f'账号 [{name}] 任务查询失败: {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 任务查询失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 任务查询失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 任务查询失败[其他]: {e}')
def share(name,token,entity_id):
try:
response = requests.get(f'https://api3.ali213.net/feedearn/sharearticle?channelID=1&entityID={entity_id}&token={token}', headers=api_headers)
response_json = response.json()
if response_json['status'] == 1:
print(f'账号 [{name}] 分享成功,奖励: {response_json["msg"]}金币')
elif response_json['status'] == 0:
print(f'账号 [{name}] 分享失败: {response_json["msg"]}')
else:
print(f'账号 [{name}] 分享失败: {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 分享失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 分享失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 分享失败[其他]: {e}')
def get_recommendList():
try:
response = requests.get('https://newapi.ali213.net/app/v1/recommendList?confirmNo=0&keyword=&lastId=&navId=2&pageNo=1&pageNum=10', headers=api_headers)
response_json = response.json()
if response_json['code'] == 200:
print('推荐列表数据获取成功')
data = response_json['data']['list']
integer_jump_urls = []
for item in data:
if isinstance(item.get('jumpUrl'), int):
integer_jump_urls.append(item['jumpUrl'])
return integer_jump_urls
else:
print('推荐列表数据获取失败')
log(f'推荐列表数据获取失败\n')
return []
except requests.exceptions.RequestException as e:
print(f'推荐列表数据获取失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'推荐列表数据获取失败[JSON]: {e}')
except Exception as e:
print(f'推荐列表数据获取失败[其他]: {e}')
def get_square():
try:
response = requests.get('https://club.ali213.net/application/forum/square?id=0', headers=api_headers)
response_json = response.json()
if response_json['code'] == 111 and response_json['msg'] == 'success':
print('BBS社区数据获取成功')
threadList = response.json()['data']['threadList']
thread_id = []
for item in threadList:
thread_id.append(item['id'])
return thread_id
else:
print('BBS社区数据获取失败')
log(f'BBS社区数据获取失败\n')
return []
except requests.exceptions.RequestException as e:
print(f'BBS社区数据获取失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'BBS社区数据获取失败[JSON]: {e}')
except Exception as e:
print(f'BBS社区数据获取失败[其他]: {e}')
def readingreward(name,token,threadid):
try:
response = requests.get(f'https://club.ali213.net/application/thread/readingreward?threadid={threadid}&token={token}', headers=api_headers)
response_json = response.json()
if response_json['code'] == 111 and response_json['msg'] == 'success':
print(f'账号 [{name}] 阅读奖励成功,奖励: {response_json["data"]}金币')
elif response_json['code'] == -1 and response_json['msg'] == 'failed':
print(f'账号 [{name}] 阅读奖励失败: 已领取过奖励')
else:
print(f'账号 [{name}] 阅读奖励失败: {response.text}')
except requests.exceptions.RequestException as e:
print(f'账号 [{name}] 阅读奖励失败[请求]: {e}')
except json.JSONDecodeError as e:
print(f'账号 [{name}] 阅读奖励失败[JSON]: {e}')
except Exception as e:
print(f'账号 [{name}] 阅读奖励失败[其他]: {e}')
if __name__ == '__main__':
print('*'*50)
all_user = len(yxwlogin)
print(f"检测到环境变量中存在{all_user}个账号")
for yxwlogin_item in yxwlogin:
get_userdata(yxwlogin_item)
user_data = get_user_ids_and_tokens()
if not user_data:
print("未读取到用户数据,程序退出")
exit(0)
else:
print(f"读取到{len(user_data)}个账号")
recommendList = get_recommendList()
square = get_square()
print('*'*50)
for item in user_data:
print('-' * 50)
log('-' * 35)
user_phone = item['phone_key']
user_name = item['user_name']
user_token = item['token']
new_user_token = check_token(user_phone,user_token)
if new_user_token:
check_sign(user_name, new_user_token)
newusercheck(user_name, new_user_token)
luckbox_cookies(user_phone, user_token)
# usermission(user_name, new_user_token)
if recommendList:
for entity_id in recommendList:
share(user_name, new_user_token, entity_id)
time.sleep(1)
else:
print(f'账号 [{user_phone}] 推荐列表为空')
if square:
for thread_id in square:
readingreward(user_name, new_user_token, thread_id)
time.sleep(1)
else:
print(f'账号 [{user_phone}] BBS社区列表为空')
userinfo(user_phone, new_user_token)
else:
print(f'账号 [{user_phone}] 获取数据失败')
continue
try:
send_notification_message(title='游侠网开宝箱') # 发送通知
except Exception as e:
print('推送失败:' + str(e))

View File

@@ -0,0 +1,118 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/yxw_luckbox.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/yxw_luckbox.py
# Repo: lksky8/sign-ql
# Path: yxw_luckbox.py
# UploadedAt: 2025-08-21T12:12:12Z
# SHA256: 7951192443b96cec1fe801de769343a2e080be439b46c9b2bfb4372a4cdfe2e1
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
'''
作者https://github.com/lksky8/sign-ql/
日期2025-8-21
软件:游侠网-开宝箱
功能每隔三小时自动开宝箱领取50金币
定时0,5 */3 * * *
'''
import json
import requests
import time
send_msg = ''
one_msg = ''
def log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'{cont}\n'
send_msg += f'{cont}\n'
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
def get_user_ids_and_tokens(file_path='youxia_data.json'):
try:
# 1. 读取JSON文件
with open(file_path, 'r', encoding='utf-8') as f:
phone_data = json.load(f)
# 2. 遍历每个手机号
results = []
for phone_key, data in phone_data.items():
user_name = data.get('nickname')
user_token = data.get('token')
api3AliSSO_cookie = data.get('api3AliSSO')
if user_name and user_token: # 确保userId和token存在
results.append({
'phone_key': phone_key,
'user_name': user_name,
'api3AliSSO': api3AliSSO_cookie
})
# print(f"手机号: {phone_key}, userId: {user_id}, token: {token}")
return results
except FileNotFoundError:
print(f"文件 {file_path} 不存在!")
return []
except json.JSONDecodeError:
print(f"文件 {file_path} 格式错误!")
return []
def do_sign(phone, user_name, ck):
headers = {
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 ali213app"
}
cookies = {
"api3AliSSO": ck
}
try:
response = requests.get("https://api3.ali213.net/feedearn/luckybox?action=get", headers=headers,cookies=cookies)
response.raise_for_status()
response_json = response.json()
if response_json['logined']:
print(f"账号 [{phone}][{user_name}] 登录成功CK有效")
print(f"账号 [{phone}][{user_name}] {response_json['data']['msg']}")
if response_json['data']['status'] == 1 and response_json['data']['msg'] == '领取成功':
print(f"账号 [{phone}][{user_name}] 获得{response_json['data']['coins']}金币")
else:
print(f"账号 [{phone}][{user_name}] 登录失败CK无效")
log(f"账号 [{phone}][{user_name}] 登录失败CK无效")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
except json.JSONDecodeError as e:
print(f"JSON解析错误: {e}")
except Exception as e:
print(f"其他错误: {e}")
if __name__ == '__main__':
user_data = get_user_ids_and_tokens()
if not user_data:
print("未读取到用户数据,程序退出")
exit(0)
else:
print(f"读取到{len(user_data)}个账号")
for item in user_data:
phone = item['phone_key']
user_name = item['user_name']
ck = item['api3AliSSO']
do_sign(phone, user_name, ck)
time.sleep(1)
print("-" * 50)
try:
send_notification_message(title='游侠网开宝箱') # 发送通知
except Exception as e:
print('推送失败:' + str(e))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,297 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/jksign.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/jksign.py
# Repo: lksky8/sign-ql
# Path: jksign.py
# UploadedAt: 2025-12-07T17:42:50Z
# SHA256: b722f903ef41b1cab2540fc2a7b84bb51cb2e8d354783a225e3c364b0799a4e6
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
方舟健客app签到
作者https://github.com/lksky8/sign-ql
日期2025-12-5
使用方法APP抓登录包获取refresh_token填入jktoken
支持多用户运行,多用户用&或者@隔开
则变量为
export jktoken="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9........&eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9........"
每日签到一次即可
cron: 0 5 * * *
const $ = new Env("方舟健客签到");
"""
import time
import requests
import re
import os
import datetime
import hashlib
#推送开关开启为True关闭为False
push_message = True
def md5_encrypt(text):
md5_hash = hashlib.md5()
md5_hash.update(text.encode('utf-8'))
md5_result = md5_hash.hexdigest()
return md5_result
def time13():
now = datetime.datetime.now()
timestamp_ms = int(now.timestamp() * 1000) + (now.microsecond // 1000)
return timestamp_ms
def get_jkx():
a = time13() - 1500000000000
j = a % 999983
j2 = a % 9973
h = "6470"
md5_1 = md5_encrypt(f"39CC231D-C1F9-48DC-93DA-4CA0EA53C141{j}{h}")
md5_2 = md5_encrypt(f"{md5_1}{j2}{h}")
return f'{j}#{md5_2}#{j2}#{h}'
api_headers = {
'Host': 'acgi.jianke.com',
'Accept': 'application/json, text/plain, */*',
'Sec-Fetch-Site': 'same-site',
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'platform': 'APP',
'Sec-Fetch-Mode': 'cors',
'Origin': 'https://app-hybrid.jianke.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 jiankeMall/6.47.0 JiankeMall/6.47.0',
'Referer': 'https://app-hybrid.jianke.com/',
'Content-Type': 'application/json;charset=utf-8',
'Sec-Fetch-Dest': 'empty',
}
api_headers2 = {
'Host': 'fe-acgi.jianke.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 jiankeMall/6.47.0',
'versionName': '6.47.0',
'X-JK-UDID': '39CC231D-C1F9-48DC-93DA-4CA0EA53C141',
'versionCode': '6470',
'X-JK-X': get_jkx(),
'platform': 'APP',
'Accept-Language': 'zh-Hans-CN;q=1',
'Accept': 'application/json',
'Content-Type': 'application/json',
}
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'{cont}\n'
send_msg += f'{cont}\n'
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
def refresh_token(token):
headers = {'Content-Type': 'application/json; charset=utf-8','User-Agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.135 Mobile Safari/537.36 jiankeMall/6.26.0(w1080*h2029)','Host': 'acgi.jianke.com','organizationCode': 'app.jianke'}
data = {'refreshToken': token }
response = requests.post('https://acgi.jianke.com/passport/account/refreshToken', json=data, headers=headers)
if '授权失败' in response.text:
print('账号刷新token已失效请重新获取')
Log('账号刷新token已失效请重新获取')
return False
else:
response_json = response.json()
if response_json['token_type'] == 'bearer':
print("账号token刷新成功新的access_token已填入:\n" + response_json['access_token'])
return response_json['access_token']
else:
print("Failed to send POST request. Status Code:", response.status_code)
print("出错了:", response.text)
def do_sign(new_token,user_name):
# headers = api_headers2.copy()
# headers['Authorization'] = f'bearer {new_token}'
headers = {'Authorization':'bearer ' + new_token,'User-Agent': 'Mozilla/5.0 (Linux; Android 10; MI 8 Build/QKQ1.190828.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/131.0.6778.135 Mobile Safari/537.36 jiankeMall/6.26.0(w1080*h2029)','X-JK-X': get_jkx(),'versionName': '6.47.0','X-JK-UDID': '39CC231D-C1F9-48DC-93DA-4CA0EA53C141'}
dl = requests.put('https://acgi.jianke.com/v2/member/signConfig/sign', headers=headers)
dl_json = dl.json()
if dl.status_code == 200:
print(f"[{user_name}] 本次签到获得:{dl_json['coinNum']}金币,今天是本周第{dl_json['cumulativeNum']}天签到")
Log(f"\n{user_name}] 本次签到获得:{dl_json['coinNum']}金币,今天是本周第{dl_json['cumulativeNum']}天签到")
elif dl_json['message'] == '今日已签到':
print(f'[{user_name}] 今天已经签到了')
Log(f'\n[{user_name}] 今天已经签到了')
else:
print("出错了:", dl.text)
def today_question(new_token,task_id,user_name):
headers = api_headers.copy()
headers['Authorization'] = f'bearer {new_token}'
response = requests.get('https://acgi.jianke.com/support/coin/task/daily-tasks/today-question', headers=headers)
response_json = response.json()
if response_json['code'] == '0' and response_json['message'] == 'success':
print(f'[{user_name}]【每日一答】 任务获取成功')
question_id = response_json['data']['id']
rightChoice = response_json['data']['rightChoice']
json_data = {
'id': str(task_id),
'questionItem': {
'id': question_id,
'rightChoice': rightChoice,
'userChoice': rightChoice,
'roundNum': 1,
},
}
response = requests.post('https://acgi.jianke.com/support/coin/task/complete', headers=headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['message'] == 'success':
print(f'[{user_name}]【每日一答】 任务完成')
Log(f'[{user_name}]【每日一答】 任务完成')
else:
print(f'[{user_name}]【每日一答】 {response_json["message"]}')
Log(f'[{user_name}]【每日一答】 {response_json["message"]}')
else:
print(f'[{user_name}]【每日一答】 任务获取失败')
Log(f'[{user_name}]【每日一答】 任务获取失败')
print(response.text)
def get_today_tasks(new_token, user_name):
headers = api_headers.copy()
headers['Authorization'] = f'bearer {new_token}'
response = requests.get('https://acgi.jianke.com/support/coin/task/daily-tasks', headers=headers)
if response.status_code == 200:
response_json = response.json()
task_list = []
for item in response_json['data']:
task_id = item['id']
task_name = item['taskName']
task_list.append({'task_id': task_id, 'task_name': task_name})
return task_list
else:
print(f'{user_name} 获取任务数据失败')
print(response.text)
return None
def do_task(new_token,user_name, task_id, task_name):
headers = api_headers.copy()
headers['Authorization'] = f'bearer {new_token}'
json_data = {
'id': str(task_id)
}
response = requests.post('https://acgi.jianke.com/support/coin/task/complete', headers=headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['message'] == 'success':
print(f'[{user_name}]【{task_name}】 任务完成')
Log(f'[{user_name}]【{task_name}】 任务完成')
else:
print(f'[{user_name}]【{task_name}{response_json["message"]}')
Log(f'[{user_name}]【{task_name}{response_json["message"]}')
def task_receive(new_token, user_name, task_id,task_name):
headers = api_headers.copy()
headers['Authorization'] = f'bearer {new_token}'
json_data = {
'id': task_id,
}
response = requests.post('https://acgi.jianke.com/support/coin/task/receive', headers=headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['message'] == 'success':
print(f'[{user_name}]【{task_name}】 任务奖励:领取成功')
elif response_json['message'] == '奖励领取失败':
print(f'[{user_name}]【{task_name}】 任务奖励:领取失败')
Log(f'[{user_name}]【{task_name}】 任务奖励:领取失败')
else:
print('奖励领取失败')
print(response.text)
def get_coin(new_token, user_name):
headers = api_headers.copy()
headers['Authorization'] = f'bearer {new_token}'
response = requests.get('https://acgi.jianke.com/v1/coin/balance', headers=headers)
if response.status_code == 200:
response_json = response.json()
print(f'[{user_name}] 当前健康币:{response_json["balance"]}')
Log(f'[{user_name}] 当前健康币:{response_json["balance"]}')
else:
print('获取金币数失败')
print(response.text)
def get_userinfo(new_token):
headers = api_headers2.copy()
headers['Authorization'] = f'bearer {new_token}'
response = requests.get('https://fe-acgi.jianke.com/v5/userCenter', headers=headers)
response_json = response.json()
if response_json['statusCode'] == 200:
return response_json['data']['memberInfo']['nickName']
else:
print('获取用户信息失败')
print(response.text)
return None
if __name__ == '__main__':
if 'jktoken' in os.environ:
jktoken = re.split("@|&", os.environ.get("jktoken"))
print(f'查找到{len(jktoken)}个账号')
else:
jktoken = []
print('未填写 jktoken 变量')
if jktoken:
try:
z = 1
for ck in jktoken:
print(f'登录第{z}个账号')
print('----------------------\n')
access_token = refresh_token(ck)
if access_token:
user_nickname = get_userinfo(access_token)
print(f'[{user_nickname}] 刷新token成功')
print('\n开始签到操作>>>>>>>>>>\n')
do_sign(access_token, user_nickname)
print('\n开始执行任务>>>>>>>>>>\n')
task_data = get_today_tasks(access_token, user_nickname)
if task_data:
for task in task_data:
task_id = task['task_id']
task_name = task['task_name']
# print(f'[{user_nickname}] 开始执行任务:{task_name}')
if task_name == '每日一答':
today_question(access_token, task_id, user_nickname)
time.sleep(1)
task_receive(access_token, user_nickname, task_id, task_name)
time.sleep(2)
continue
if task_name == '下单返币':
continue
if task_name == '打开健客医生App':
continue
do_task(access_token, user_nickname, task_id, task_name)
time.sleep(1)
task_receive(access_token, user_nickname, task_id, task_name)
time.sleep(3)
get_coin(access_token, user_nickname)
print('\n----------------------')
z = z + 1
except Exception as e:
print('未知错误:' + str(e))
if push_message:
try:
send_notification_message(title='方舟健客') # 发送通知
except Exception as e:
print('推送失败:' + str(e))

View File

@@ -0,0 +1,389 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/xxcd.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/xxcd.py
# Repo: lksky8/sign-ql
# Path: xxcd.py
# UploadedAt: 2025-09-01T15:45:21Z
# SHA256: 40e3aef421127efd0fe80201c786cf341993dd4e8318fe4f8456a912aef026e0
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
星星充电签到
作者https://github.com/lksky8/sign-ql
日期2025-09-01
使用方法打开app随便抓一个包把头部'Authorization'内容填入 export startoken=""
另外可以再填入cityid(抓包获取), export starcityid=""可填可不填
支持多用户运行,多用户用&或者@隔开
export startoken="eyJ0eXAiOiJKV1QiLCJhbGciOiJIU1NiJ9..&eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1J9.."
export starcityid=""
每天运行一次即可
cron: 0 7 * * *
const $ = new Env("星星充电签到");
"""
import requests
import re
import os
import datetime
import hashlib
import time
if 'startoken' in os.environ:
startoken = re.split("@|&",os.environ.get("startoken"))
print(f'查找到{len(startoken)}个账号\n')
else:
startoken =['']
print('无startoken变量')
if 'starcityid' in os.environ:
cityid = os.environ.get("starcityid")
print(f'已填入cityid:{cityid}')
else:
cityid = '440000'
print('没有填写cityid,系统默认使用440000')
def md5_encrypt(text):
md5_hash = hashlib.md5()
md5_hash.update(text.encode('utf-8'))
md5_result = md5_hash.hexdigest()
return md5_result
def time13():
now = datetime.datetime.now()
timestamp_ms = int(now.timestamp() * 1000) + (now.microsecond // 1000)
return str(timestamp_ms)
def find_task_ids(data):
this_week_task_id = None
this_month_task_id = None
for model in data:
for task in model['taskList']:
if task['taskName'] == '本周充电任务':
this_week_task_id = task['taskId']
elif task['taskName'] == '本月充电任务':
this_month_task_id = task['taskId']
return this_week_task_id, this_month_task_id
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'{cont}\n'
send_msg += f'{cont}\n'
# 发送通知消息
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
def sign(token):
try:
timestamp = time13()
signature = md5_encrypt(f'nonce=2b4aa7d9-4137-4e51-94e3-7b7355bf202a&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://scm-app-h5.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': cityid,
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': 'application/json, text/plain, */*',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
'Content-Type': 'application/x-www-form-urlencoded',
}
data = {
'nonce': '2b4aa7d9-4137-4e51-94e3-7b7355bf202a',
'timestamp': timestamp,
'userId': '',
}
response = requests.post('https://gateway.starcharge.com/apph5/webApiV2/starPoint/sign',headers=headers, data=data)
response_json = response.json()
if response_json['code'] == '200':
print(f"签到成功:获得{response_json['data']['basePoint']}积分,已连续签到{response_json['data']['continuousDay']}")
Log(f"签到成功:获得{response_json['data']['basePoint']}积分,已连续签到{response_json['data']['continuousDay']}")
return True
elif response_json['code'] == '402':
print('用户数据获取失败,重新尝试获取数据')
return False
else:
print("签到失败:", response.text)
return False
except requests.exceptions.RequestException as e:
print("Failed to send POST request. Status Code:", response.status_code)
except Exception as e:
print("签到出错了:", e)
def Get_list(token):
try:
timestamp = time13()
signature = md5_encrypt(f'city={cityid}&nonce=1b93f289-32ee-4616-a860-5aef04c6c048&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'Accept': 'application/json, text/plain, */*',
'memberAdType': '0-0',
'Authorization': token,
'timestamp': timestamp,
'appVersion': '7.40.0',
'channel-id': '98',
'referrer': 'web',
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'signature': signature,
'positCity': cityid,
'Origin': 'https://scm-app-h5.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_8_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/userTask/model/list?city={cityid}&nonce=1b93f289-32ee-4616-a860-5aef04c6c048',headers=headers)
response_json = response.json()
if response_json['code'] == '200':
return response_json['data']
else:
print("获取任务列表失败:", response.text)
return False
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("获取任务列表出错了:", e)
def Do_task(task_id,token):
try:
timestamp = time13()
signature = md5_encrypt(f'nonce=4f63ecd8-e342-4e33-94a4-81bdfd040235&taskId={task_id}&taskType=1&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'Accept': 'application/json, text/plain, */*',
'memberAdType': '0-0',
'Authorization': token,
'timestamp': timestamp,
'appVersion': '7.40.0',
'channel-id': '98',
'referrer': 'web',
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'signature': signature,
'positCity': cityid,
'Origin': 'https://scm-app-h5.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_8_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/userTask/get?taskId={task_id}&taskType=1&nonce=4f63ecd8-e342-4e33-94a4-81bdfd040235', headers=headers)
response_json = response.json()
if response_json['code'] == None:
return response_json['text']
elif response_json['code'] == '200' and response_json['text'] == None :
return '任务已领取'
else:
print("做任务:", response.text)
return False
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
def Get_info(token):
try:
timestamp = time13()
signature = md5_encrypt(f'city={cityid}&nonce=b7e92ec1-813f-4ec2-ab8a-e91289604733&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://scm-app-h5.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': cityid,
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': 'application/json, text/plain, */*',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
'Content-Type': 'application/x-www-form-urlencoded',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/v2/webApiV2/star/point/user?city={cityid}&nonce=b7e92ec1-813f-4ec2-ab8a-e91289604733', headers=headers)
response_json = response.json()
if response_json['code'] == '200':
print(f'用户({response_json["data"]["nickName"]})目前金币:{response_json["data"]["points"]}')
Log(f'用户({response_json["data"]["nickName"]})目前金币:{response_json["data"]["points"]}\n')
else:
print('用户数据查询失败:' + response.text)
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("查询用户数据出错了:", e)
def Get_user_info(token):
try:
timestamp = time13()
signature = md5_encrypt(f'cityCode={cityid}&nonce=b6efee74-2ad5-43b3-bf3f-2435613c7c9d&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'Accept': 'application/json, text/plain, */*',
'Authorization': token,
'timestamp': timestamp,
'Sec-Fetch-Site': 'same-site',
'appVersion': '7.40.0',
'channel-id': '98',
'referrer': 'web',
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'signature': signature,
'Sec-Fetch-Mode': 'cors',
'Origin': 'https://scm-app-h5.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'positCity': cityid,
'Sec-Fetch-Dest': 'empty',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/user/getUserBaseInfo?cityCode={cityid}&nonce=b6efee74-2ad5-43b3-bf3f-2435613c7c9d', headers=headers)
response_data = response.json()
if response_data['code'] == '200':
if response_data['data']['appVipType'] == 1:
print(f'用户({response_data["data"]["nickName"]})已开通VIP到期日{response_data["data"]["appVipExpiration"]}')
vip_sign(token)
check_vip_sign(token)
else:
print(f'用户({response_data["data"]["nickName"]}) 未开通VIP')
else:
print('查询是否VIP失败:' + response.text)
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("查询是否VIP出错了:", e)
def vip_sign(token):
try:
timestamp = time13()
signature = md5_encrypt('nonce=8f396424-3729-4f50-bf67-bfb8fe38b9c5&timestamp='+timestamp+'&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://scm-app-h5.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': '440600',
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': 'application/json, text/plain, */*',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
'Content-Type': 'application/x-www-form-urlencoded',
}
data = {
'nonce': '8f396424-3729-4f50-bf67-bfb8fe38b9c5',
'timestamp': timestamp,
'userId': '',
}
response = requests.post('https://gateway.starcharge.com/apph5/webApiV2/member/v5/home/sign',headers=headers, data=data).json()
if response['code'] == '200':
print(f"VIP任务签到成功")
else:
print("VIP任务签到失败" + response['text'])
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("出错了:", e)
def check_vip_sign(token):
try:
timestamp = time13()
signature = md5_encrypt(f'cycleType=1&nonce=2d3d2147-dbce-42b4-8fa9-9268b4fa580f&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'memberAdType': '0-0',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://app-taro.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://app-taro.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': '440600',
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/member/v5/home/sign/records?cycleType=1&nonce=2d3d2147-dbce-42b4-8fa9-9268b4fa580f&timestamp={timestamp}&userId=',headers=headers).json()
if response['code'] == '200':
print(f"VIP任务已连续签到{response['data']['continuousDays']}")
else:
print("VIP任务查询失败" + response)
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("出错了:", e)
def main():
z = 1
for ck in startoken:
try:
print(f'登录第{z}个账号')
print('----------------------')
print('\n开始签到操作>>>>>>>>>>\n')
while True:
if sign(ck):
break
time.sleep(3)
print('\n完成日常任务>>>>>>>>>>\n')
this_week_id, this_month_id = find_task_ids(Get_list(ck))
print("本周充电任务:", Do_task(this_week_id,ck))
print("本月充电任务:", Do_task(this_month_id,ck))
print('\n获取用户信息>>>>>>>>>>\n')
Get_info(ck)
Get_user_info(ck)
print('\n----------------------')
z = z + 1
except Exception as e:
print(e)
if __name__ == '__main__':
try:
main()
except Exception as e:
print(e)
try:
send_notification_message(title='星星充电') # 发送通知
except Exception as e:
print(e)

View File

@@ -0,0 +1,389 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/xxcd.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/xxcd.py
# Repo: lksky8/sign-ql
# Path: xxcd.py
# UploadedAt: 2026-05-23T06:33:21Z
# SHA256: 40e3aef421127efd0fe80201c786cf341993dd4e8318fe4f8456a912aef026e0
# Category: web版/账密
# Evidence: web/H5关键词 + username/password/login
"""
星星充电签到
作者https://github.com/lksky8/sign-ql
日期2025-09-01
使用方法打开app随便抓一个包把头部'Authorization'内容填入 export startoken=""
另外可以再填入cityid(抓包获取), export starcityid=""可填可不填
支持多用户运行,多用户用&或者@隔开
export startoken="eyJ0eXAiOiJKV1QiLCJhbGciOiJIU1NiJ9..&eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1J9.."
export starcityid=""
每天运行一次即可
cron: 0 7 * * *
const $ = new Env("星星充电签到");
"""
import requests
import re
import os
import datetime
import hashlib
import time
if 'startoken' in os.environ:
startoken = re.split("@|&",os.environ.get("startoken"))
print(f'查找到{len(startoken)}个账号\n')
else:
startoken =['']
print('无startoken变量')
if 'starcityid' in os.environ:
cityid = os.environ.get("starcityid")
print(f'已填入cityid:{cityid}')
else:
cityid = '440000'
print('没有填写cityid,系统默认使用440000')
def md5_encrypt(text):
md5_hash = hashlib.md5()
md5_hash.update(text.encode('utf-8'))
md5_result = md5_hash.hexdigest()
return md5_result
def time13():
now = datetime.datetime.now()
timestamp_ms = int(now.timestamp() * 1000) + (now.microsecond // 1000)
return str(timestamp_ms)
def find_task_ids(data):
this_week_task_id = None
this_month_task_id = None
for model in data:
for task in model['taskList']:
if task['taskName'] == '本周充电任务':
this_week_task_id = task['taskId']
elif task['taskName'] == '本月充电任务':
this_month_task_id = task['taskId']
return this_week_task_id, this_month_task_id
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'{cont}\n'
send_msg += f'{cont}\n'
# 发送通知消息
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
def sign(token):
try:
timestamp = time13()
signature = md5_encrypt(f'nonce=2b4aa7d9-4137-4e51-94e3-7b7355bf202a&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://scm-app-h5.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': cityid,
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': 'application/json, text/plain, */*',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
'Content-Type': 'application/x-www-form-urlencoded',
}
data = {
'nonce': '2b4aa7d9-4137-4e51-94e3-7b7355bf202a',
'timestamp': timestamp,
'userId': '',
}
response = requests.post('https://gateway.starcharge.com/apph5/webApiV2/starPoint/sign',headers=headers, data=data)
response_json = response.json()
if response_json['code'] == '200':
print(f"签到成功:获得{response_json['data']['basePoint']}积分,已连续签到{response_json['data']['continuousDay']}")
Log(f"签到成功:获得{response_json['data']['basePoint']}积分,已连续签到{response_json['data']['continuousDay']}")
return True
elif response_json['code'] == '402':
print('用户数据获取失败,重新尝试获取数据')
return False
else:
print("签到失败:", response.text)
return False
except requests.exceptions.RequestException as e:
print("Failed to send POST request. Status Code:", response.status_code)
except Exception as e:
print("签到出错了:", e)
def Get_list(token):
try:
timestamp = time13()
signature = md5_encrypt(f'city={cityid}&nonce=1b93f289-32ee-4616-a860-5aef04c6c048&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'Accept': 'application/json, text/plain, */*',
'memberAdType': '0-0',
'Authorization': token,
'timestamp': timestamp,
'appVersion': '7.40.0',
'channel-id': '98',
'referrer': 'web',
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'signature': signature,
'positCity': cityid,
'Origin': 'https://scm-app-h5.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_8_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/userTask/model/list?city={cityid}&nonce=1b93f289-32ee-4616-a860-5aef04c6c048',headers=headers)
response_json = response.json()
if response_json['code'] == '200':
return response_json['data']
else:
print("获取任务列表失败:", response.text)
return False
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("获取任务列表出错了:", e)
def Do_task(task_id,token):
try:
timestamp = time13()
signature = md5_encrypt(f'nonce=4f63ecd8-e342-4e33-94a4-81bdfd040235&taskId={task_id}&taskType=1&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'Accept': 'application/json, text/plain, */*',
'memberAdType': '0-0',
'Authorization': token,
'timestamp': timestamp,
'appVersion': '7.40.0',
'channel-id': '98',
'referrer': 'web',
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'signature': signature,
'positCity': cityid,
'Origin': 'https://scm-app-h5.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_8_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/userTask/get?taskId={task_id}&taskType=1&nonce=4f63ecd8-e342-4e33-94a4-81bdfd040235', headers=headers)
response_json = response.json()
if response_json['code'] == None:
return response_json['text']
elif response_json['code'] == '200' and response_json['text'] == None :
return '任务已领取'
else:
print("做任务:", response.text)
return False
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
def Get_info(token):
try:
timestamp = time13()
signature = md5_encrypt(f'city={cityid}&nonce=b7e92ec1-813f-4ec2-ab8a-e91289604733&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://scm-app-h5.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': cityid,
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': 'application/json, text/plain, */*',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
'Content-Type': 'application/x-www-form-urlencoded',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/v2/webApiV2/star/point/user?city={cityid}&nonce=b7e92ec1-813f-4ec2-ab8a-e91289604733', headers=headers)
response_json = response.json()
if response_json['code'] == '200':
print(f'用户({response_json["data"]["nickName"]})目前金币:{response_json["data"]["points"]}')
Log(f'用户({response_json["data"]["nickName"]})目前金币:{response_json["data"]["points"]}\n')
else:
print('用户数据查询失败:' + response.text)
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("查询用户数据出错了:", e)
def Get_user_info(token):
try:
timestamp = time13()
signature = md5_encrypt(f'cityCode={cityid}&nonce=b6efee74-2ad5-43b3-bf3f-2435613c7c9d&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'Accept': 'application/json, text/plain, */*',
'Authorization': token,
'timestamp': timestamp,
'Sec-Fetch-Site': 'same-site',
'appVersion': '7.40.0',
'channel-id': '98',
'referrer': 'web',
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'signature': signature,
'Sec-Fetch-Mode': 'cors',
'Origin': 'https://scm-app-h5.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'positCity': cityid,
'Sec-Fetch-Dest': 'empty',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/user/getUserBaseInfo?cityCode={cityid}&nonce=b6efee74-2ad5-43b3-bf3f-2435613c7c9d', headers=headers)
response_data = response.json()
if response_data['code'] == '200':
if response_data['data']['appVipType'] == 1:
print(f'用户({response_data["data"]["nickName"]})已开通VIP到期日{response_data["data"]["appVipExpiration"]}')
vip_sign(token)
check_vip_sign(token)
else:
print(f'用户({response_data["data"]["nickName"]}) 未开通VIP')
else:
print('查询是否VIP失败:' + response.text)
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("查询是否VIP出错了:", e)
def vip_sign(token):
try:
timestamp = time13()
signature = md5_encrypt('nonce=8f396424-3729-4f50-bf67-bfb8fe38b9c5&timestamp='+timestamp+'&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://scm-app-h5.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://scm-app-h5.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': '440600',
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': 'application/json, text/plain, */*',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
'Content-Type': 'application/x-www-form-urlencoded',
}
data = {
'nonce': '8f396424-3729-4f50-bf67-bfb8fe38b9c5',
'timestamp': timestamp,
'userId': '',
}
response = requests.post('https://gateway.starcharge.com/apph5/webApiV2/member/v5/home/sign',headers=headers, data=data).json()
if response['code'] == '200':
print(f"VIP任务签到成功")
else:
print("VIP任务签到失败" + response['text'])
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("出错了:", e)
def check_vip_sign(token):
try:
timestamp = time13()
signature = md5_encrypt(f'cycleType=1&nonce=2d3d2147-dbce-42b4-8fa9-9268b4fa580f&timestamp={timestamp}&userId=')[0:18].upper()
headers = {
'Host': 'gateway.starcharge.com',
'memberAdType': '0-0',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
'Referer': 'https://app-taro.starcharge.com/',
'appVersion': '7.40.0',
'Origin': 'https://app-taro.starcharge.com',
'signature': signature,
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Site': 'same-site',
'referrer': 'web',
'timestamp': timestamp,
'positCity': '440600',
'Authorization': token,
'Accept-Language': 'zh-CN,zh-Hans;q=0.9',
'Accept': '*/*',
'Content-Type': 'application/x-www-form-urlencoded',
'channel-id': '98',
'Sec-Fetch-Mode': 'cors',
}
response = requests.get(f'https://gateway.starcharge.com/apph5/webApiV2/member/v5/home/sign/records?cycleType=1&nonce=2d3d2147-dbce-42b4-8fa9-9268b4fa580f&timestamp={timestamp}&userId=',headers=headers).json()
if response['code'] == '200':
print(f"VIP任务已连续签到{response['data']['continuousDays']}")
else:
print("VIP任务查询失败" + response)
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
except Exception as e:
print("出错了:", e)
def main():
z = 1
for ck in startoken:
try:
print(f'登录第{z}个账号')
print('----------------------')
print('\n开始签到操作>>>>>>>>>>\n')
while True:
if sign(ck):
break
time.sleep(3)
print('\n完成日常任务>>>>>>>>>>\n')
this_week_id, this_month_id = find_task_ids(Get_list(ck))
print("本周充电任务:", Do_task(this_week_id,ck))
print("本月充电任务:", Do_task(this_month_id,ck))
print('\n获取用户信息>>>>>>>>>>\n')
Get_info(ck)
Get_user_info(ck)
print('\n----------------------')
z = z + 1
except Exception as e:
print(e)
if __name__ == '__main__':
try:
main()
except Exception as e:
print(e)
try:
send_notification_message(title='星星充电') # 发送通知
except Exception as e:
print(e)

View File

@@ -0,0 +1,487 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/cloud189.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/cloud189.py
# Repo: lksky8/sign-ql
# Path: cloud189.py
# UploadedAt: 2025-09-06T12:51:46Z
# SHA256: 7c90c2eb0032873254db7819a42440cd062ae32af3fa537efc7c295c0e1da804
# Category: 微信小程序/抓包版
# Evidence: appid/openid/session_key/encryptedData等小程序字段
"""
天翼云盘签到
作者https://github.com/lksky8/sign-ql
最后更新日期2025-9-6
如脚本无法运行先在青龙依赖管理的Python里面安装pycryptodome这个包
食用方法打开天翼云盘app抓请求url=api.cloud.189.cn/guns/getPageBanners.action里面accessToken(一般在请求头里)填到变量cloud189_token里面即可
支持多用户运行
多用户用&或者@隔开
例如账号110086 账号2 1008611
则变量为
export cloud189_token="10086&1008611"
cron: 50 1,18 * * *
"""
import requests
import time
import hmac
import hashlib
import base64
import os
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Cipher import PKCS1_v1_5
import re
from urllib.parse import unquote
from datetime import datetime, timedelta
if 'cloud189_token' in os.environ:
cloud189_token = re.split("@|&",os.environ.get("cloud189_token"))
print(f'查找到{len(cloud189_token)}个账号')
else:
cloud189_token =['']
print('无cloud189_token变量')
aes_iv = "Zx8dG46ax3Mc8Mj2".encode() # 16 字节
aes_key = "bf8395f745c04f23".encode() # 16 字节
# RSA_PUBLIC_KEY_PEM = """-----BEGIN PUBLIC KEY-----
# MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaoVRMEdxN2LZj7f0UL/0OMJJj
# GuD1OgDRF4WTY1ZCupektwYvS5nU2FelBJ9bV5dv5MVYAp6r9rOkRwE+PEvgwaVP
# ghwfNg1ljCkQ2QFNAmwKHF/sjgHsHu94IbYL7MokSETU6Y4d5k+Vm/3qvqxZs8Yf
# 1HGx3ojEU6Atxqp/QwIDAQAB
# -----END PUBLIC KEY-----"""
RSA_PUBLIC_KEY_PEM = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC72L803mNmrQgyvaU
t115S5gSHuDcS+nGdqBakHYqFShEwrEaqKsr2Z/7DQt9AobB0ne2vIS
UW0tXjhgf5vfl00kT7K+J4j+t3WLkQ6Zwc9KtZHkSW6/fkFSC1EnShP
YLsG6rHYa5+wfefOY2P7yEFRsd5DGCqHNWkzOZclsXawIDAQAB
-----END PUBLIC KEY-----"""
# AES CBC 加密函数
def aes_cbc_encrypt(plaintext, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
padded_plaintext = pad(plaintext.encode('utf-8'), AES.block_size)
ciphertext = cipher.encrypt(padded_plaintext)
return base64.b64encode(ciphertext).decode('utf-8')
# AES CBC 解密函数
def aes_cbc_decrypt(ciphertext, key, iv):
ciphertext = base64.b64decode(ciphertext)
cipher = AES.new(key, AES.MODE_CBC, iv)
padded_plaintext = cipher.decrypt(ciphertext)
plaintext = unpad(padded_plaintext, AES.block_size)
return plaintext.decode('utf-8')
def encrypt_aes_key(key):
aes_session_key = key.encode('utf-8')
rsa_public_key = RSA.import_key(RSA_PUBLIC_KEY_PEM)
rsa_cipher = PKCS1_v1_5.new(rsa_public_key)
encrypted_aes_key = rsa_cipher.encrypt(aes_session_key)
return base64.b64encode(encrypted_aes_key).decode('utf-8')
def md5_encrypt(plaintext):
md5_hash = hashlib.md5()
md5_hash.update(plaintext.encode('utf-8'))
return md5_hash.hexdigest()
def hmac_sha1_hex(key, message):
key_bytes = key.encode('utf-8')
message_bytes = message.encode('utf-8')
hmac_hash = hmac.new(key_bytes, message_bytes, hashlib.sha1)
return hmac_hash.digest().hex()
def get_task_info(data):
task_info = []
for task in data["data"]:
if not task["status"]: # 只返回未完成的任务
task_info.append({
"taskId": task["taskId"],
"taskName": task["taskName"],
})
return task_info
send_msg = ''
one_msg = ''
def log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'{cont}\n'
send_msg += f'{cont}\n'
# 发送通知消息
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
def generateRsakey():
headers = {
'Host': 'api.cloud.189.cn',
'accept': 'application/json;charset=UTF-8',
'accept-language': 'zh-cn',
'x-request-id': '26E11B6CBEB94F77A2E5615C20C06113',
'date': 'Sun, 22 Jun 2025 14:33:08 GMT',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Safari/604.1',
}
params = {
'clientType': 'TELEIPHONE',
'version': '10.3.3',
'model': 'iPhone',
'osFamily': 'iOS',
'osVersion': '15.8.3',
'clientSn': '02676BE3DD-8D86-4B4F-A666-749D1D5C9FF8',
'returnType': 'JSON',
}
response = requests.get('https://api.cloud.189.cn/security/generateRsaKey.action', params=params, headers=headers).json()
return response['pkId']
def get_AccessToken(sessionKey):
timestamp_1 = str(int(time.time()))
signature = md5_encrypt(f'AppKey=600100422&Timestamp={timestamp_1}&sessionKey={sessionKey}')
headers = {
'Host': 'api.cloud.189.cn',
'accept': 'application/json;charset=UTF-8',
'sign-type': '1',
'timestamp': timestamp_1,
'sec-fetch-site': 'same-site',
'accept-language': 'zh-CN,zh-Hans;q=0.9',
'signature': signature,
'sec-fetch-mode': 'cors',
'origin': 'https://m.cloud.189.cn',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Ecloud/10.3.3 iOS/16.6.1 clientId/027A8AB808-F7A5-431E-8B37-6BD9559D22D7 clientModel/iPhone proVersion/1.0.5',
'appkey': '600100422',
'referer': 'https://m.cloud.189.cn/',
'sec-fetch-dest': 'empty',
}
params = {
'sessionKey': sessionKey,
}
response = requests.get('https://api.cloud.189.cn/open/oauth2/getAccessTokenBySsKey.action', params=params,headers=headers).json()
return response['accessToken']
def login4MergedClient(token):
timestamp = str(int(time.time()))
appsignature = hmac_sha1_hex('fe5734c74c2f96a38157f420b32dc995',f'AppKey=600100885&Operate=POST&RequestURI=/login4MergedClient.action&Timestamp={timestamp}')
param = f'isCache=1&jgOpenId=1114a89792bbaa8d350&deviceModel=iPhone%206s%20Plus&exRetryTimes=1&accessToken={token}&networkAccessMode=WIFI&telecomsOperator=&idfa=00000000-0000-0000-0000-000000000000&clientType=TELEIPHONE&version=10.3.3&model=iPhone&osFamily=iOS&osVersion=15.8.3&clientSn=02676BE3DD-8D86-4B4F-A666-749D1D5C9FF8'
encrypted_param = aes_cbc_encrypt(param, aes_key, aes_iv)
epkey = encrypt_aes_key("bf8395f745c04f23")
pkId = generateRsakey()
headers = {
'Host': 'api.cloud.189.cn',
'content-type': 'application/x-www-form-urlencoded',
'epver': '2',
'accept': '*/*',
'epway': '3',
'timestamp': timestamp,
'appsignature': appsignature,
'accept-language': 'zh-CN,zh-Hans;q=0.9',
'x-request-id': '26E11B6CBEB94F77A2E5615C20C06113',
'epkey': epkey,
'appkey': '600100885',
'user-agent': 'Cloud189/8 CFNetwork/1410.0.3 Darwin/22.6.0',
}
data = {
'pkId': pkId,
'param': encrypted_param,
}
try:
response = requests.post('https://api.cloud.189.cn/login4MergedClient.action', headers=headers, data=data).text
ciphertext = re.search(r'<ciphertext>(.*?)</ciphertext>', response, re.DOTALL).group(1)
user_data = unquote(aes_cbc_decrypt(ciphertext, aes_key, aes_iv))
# print(user_data)
login_Name = re.search(r'<loginName>(.*?)</loginName>', user_data, re.DOTALL).group(1)
session_Key = re.search(r'<sessionKey>(.*?)</sessionKey>', user_data, re.DOTALL).group(1)
sessionSecret = re.search(r'<sessionSecret>(.*?)</sessionSecret>', user_data, re.DOTALL).group(1)
familySessionKey = re.search(r'<familySessionKey>(.*?)</familySessionKey>', user_data, re.DOTALL).group(1)
return login_Name, session_Key,sessionSecret,familySessionKey
except Exception as e:
print(e)
return False
def day_sign(sS,session_key):
gmt_time = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
signature = hmac_sha1_hex(sS,f'SessionKey={session_key}&Operate=GET&RequestURI=/mkt/userSign.action&Date={gmt_time}')
headers = {
'Host': 'api.cloud.189.cn',
'x-request-id': '26E11B6CBEB94F77A2E5615C20C06113',
'signature': signature,
'date': gmt_time,
'accept-language': 'zh-cn',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_8_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Ecloud/10.3.3 (iPhone; 02676BE3DD-8D86-4B4F-A666-749D1D5C9FF8; appStore) iOS/15.8.3',
'sessionkey': session_key,
'accept': '*/*',
}
params = {
'clientType': 'TELEIPHONE',
'version': '10.3.3',
'model': 'iPhone',
'osFamily': 'iOS',
'osVersion': '15.8.3',
'clientSn': '02676BE3DD-8D86-4B4F-A666-749D1D5C9FF8',
}
response = requests.get('https://api.cloud.189.cn/mkt/userSign.action', params=params, headers=headers).text
if 'userSignResult' in response:
print('【天翼云盘】签到成功:' + re.search(r'<resultTip>(.*?)</resultTip>', response, re.DOTALL).group(1))
log('【天翼云盘】签到成功:' + re.search(r'<resultTip>(.*?)</resultTip>', response, re.DOTALL).group(1))
else:
print('【天翼云盘】签到失败:' + response)
log('【天翼云盘】签到失败:' + response)
def vip_sign(session_key):
headers = {
'Host': 'm.cloud.189.cn',
'accept': 'application/json, text/plain, */*',
'sec-fetch-site': 'same-origin',
'sec-fetch-dest': 'empty',
'accept-language': 'zh-CN,zh-Hans;q=0.9',
'sec-fetch-mode': 'cors',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Ecloud/10.3.11 iOS/16.6.1 clientId/027A8AB808-F7A5-431E-8B37-6BD9559D22D7 clientModel/iPhone proVersion/1.0.5',
'referer': 'https://m.cloud.189.cn/zt/2025/cloud-space-receive/index.html',
}
params = {
'noCache': str(int(time.time() *1000)),
'activityId': 'ACT2025VIP2T',
'sessionKey': session_key,
'prizeId': '2T_2025VIP',
}
response = requests.get('https://m.cloud.189.cn/market/drawTargetSpace.action', params=params, headers=headers).json()
if response['code'] == '0' and response['message'] == '成功':
print('【天翼云盘】2T空间月月领:领取成功')
log('【天翼云盘】2T空间月月领:领取成功')
else:
print('【天翼云盘】2T空间月月领:' + response['message'])
log('【天翼云盘】2T空间月月领:' + response['message'])
def ssoLoginMerge(sk,skF,token):
print("" * 35 )
session = requests.Session()
timestamp = str(int(time.time()))
api_headers = {
'Host': 'm.cloud.189.cn',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_8_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Ecloud/10.3.3 iOS/15.8.3 clientId/02676BE3DD-8D86-4B4F-A666-749D1D5C9FF8 clientModel/iPhone proVersion/1.0.5',
'accept-language': 'zh-CN,zh-Hans;q=0.9',
'referer': 'https://m.cloud.189.cn/zt/2024/green-task-system/index.html?uxChannel=10021132000'
}
session.headers.update(api_headers)
params = {
'sessionKey': sk,
'sessionKeyFm': skF,
'eAccessToken': token,
'redirectUrl': 'https://m.cloud.189.cn/zt/2024/green-task-system/index.html?uxChannel=10021132000',
'rand': f'6947_{timestamp}',
}
# 获取cookie数据
session.get('https://m.cloud.189.cn/ssoLoginMerge.action', params=params)
# 签到
params = {
'sessionKey': sk,
'activityId': 'ACT2024cztx',
}
response = session.get('https://m.cloud.189.cn/market/signInNew.action', params=params)
if response.json().get('result'):
print('【绿色能量活动】签到成功')
log('【绿色能量活动】签到成功')
params = {
'sessionKey': sk,
'activityId': 'ACT2024cztx',
}
response = session.get('https://m.cloud.189.cn/market/signInNewInfo.action', params=params)
print('【绿色能量活动】已签到,今天是本周第' + str(response.json().get('data')) + '天签到')
else:
print('【绿色能量活动】签到失败:' + response.text)
log('【绿色能量活动】签到失败:' + response.text)
print("\n" + "-" * 50)
print('【绿色能量活动】获取新人专属任务')
params = {
'sessionKey': sk,
'activityId': 'ACT2024cztx',
'random': '0.48929593893531875',
'taskType': '1',
}
response = session.get('https://m.cloud.189.cn/market/getGreenTaskList.action', params=params).json()
new_task = get_task_info(response)
if len(new_task) > 0:
print('【绿色能量活动】获取到' + str(len(new_task)) + '个未完成新人专属任务')
for task in new_task:
task_id = task["taskId"]
task_name = task["taskName"]
data = {
'activityId': 'ACT2024cztx',
'sessionKey': sk,
'taskId': task_id,
}
response = session.post('https://m.cloud.189.cn/market/doGreenTask.action', data=data)
if response.json().get('data'):
print(f'【绿色能量活动--->新人专属任务】✅ 任务完成: {task_name}')
else:
print(f'【绿色能量活动--->新人专属任务】⏩ 任务已跳过: {task_name}')
time.sleep(1)
else:
print('【绿色能量活动】新人专属任务已完成,跳过操作')
print("-" * 50 + "\n")
print("-" * 50)
print('【绿色能量活动】获取AI任务')
params = {
'sessionKey': sk,
'activityId': 'ACT2024cztx',
'random': '0.3382804414050936',
'taskType': '2',
}
response = session.get('https://m.cloud.189.cn/market/getGreenTaskList.action', params=params).json()
AI_task = get_task_info(response)
if len(AI_task) > 0:
print('【绿色能量活动】获取到' + str(len(AI_task)) + '个未完成日常AI任务')
for task in AI_task:
task_id = task["taskId"]
task_name = task["taskName"]
data = {
'activityId': 'ACT2024cztx',
'sessionKey': sk,
'taskId': task_id,
}
response = session.post('https://m.cloud.189.cn/market/doGreenTask.action', data=data)
if response.json().get('data'):
print(f'【绿色能量活动--->日常AI任务】✅ 任务完成: {task_name} ')
else:
print(f'【绿色能量活动--->日常AI任务】⏩ 任务已跳过: {task_name} ')
time.sleep(1)
else:
print('【绿色能量活动】日常AI任务已完成跳过操作')
print("-" * 50 + "\n")
print("-" * 50)
print('【绿色能量活动】获取绿动任务')
params = {
'sessionKey': sk,
'activityId': 'ACT2024cztx',
'random': '0.3382804414050936',
'taskType': '3',
}
response = session.get('https://m.cloud.189.cn/market/getGreenTaskList.action', params=params).json()
AI_task = get_task_info(response)
if len(AI_task) > 0:
print('【绿色能量活动】获取到' + str(len(AI_task)) + '个未完成绿动任务')
for task in AI_task:
task_id = task["taskId"]
task_name = task["taskName"]
data = {
'activityId': 'ACT2024cztx',
'sessionKey': sk,
'taskId': task_id,
}
response = session.post('https://m.cloud.189.cn/market/doGreenTask.action', data=data)
if response.json().get('data'):
print(f'【绿色能量活动--->绿动任务】✅ 任务完成: {task_name} ')
else:
print(f'【绿色能量活动--->绿动任务】⏩ 任务已跳过: {task_name} ')
time.sleep(1)
else:
print('【绿色能量活动】绿动任务已完成,跳过操作')
print("-" * 50 + "\n")
# 获取绿色能量数据
params = {
'sessionKey': sk,
'activityId': 'ACT2024cztx',
}
response = requests.get('https://m.cloud.189.cn/market/getGreenLevelList.action', params=params).json()
print('【绿色能量活动】目前能量:' + str(response['data']['userScore']) + 'g')
log('【绿色能量活动】目前能量:' + str(response['data']['userScore']) + 'g'+ "\n")
print("" * 35 + "\n")
def main():
z = 1
for ck in cloud189_token:
try:
print('=' * 60 + '\n')
print(f'登录第{z}个账号')
print('=' * 60 + '\n')
login_result = login4MergedClient(ck)
print('\n开始签到操作>>>>>>>>>>')
if isinstance(login_result, tuple):
sessionKey = login_result[1]
sessionSecret = login_result[2]
login_name = login_result[0]
print(f'{login_name}】登录成功')
log(f'{login_name}】登录成功')
print('获取到的临时Session_key:' + sessionKey)
day_sign(sessionSecret, sessionKey)
vip_sign(sessionKey)
print("" * 35 + "\n")
ssoLoginMerge(sessionKey, login_result[3], ck)
else:
print(f'{z}个账号获取sessionKey失败请检查accessToken是否正确')
log(f'{z}个账号获取sessionKey失败请检查accessToken是否正确')
z = z + 1
except Exception as e:
print('未知错误' + str(e))
# print(get_AccessToken(''))
if __name__ == '__main__':
main()
try:
send_notification_message(title='天翼云盘签到') # 发送通知
except Exception as e:
print('推送出错:' + str(e))

View File

@@ -0,0 +1,540 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/jtc.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/jtc.py
# Repo: lksky8/sign-ql
# Path: jtc.py
# UploadedAt: 2025-10-26T12:24:47Z
# SHA256: d7fa5acdc107ddb45fd772c4bb0c9491fd48e8e3d7d18ae5a4286579151676ef
# Category: 微信小程序/抓包版
# Evidence: appid/openid/session_key/encryptedData等小程序字段
"""
捷停车签到
作者https://github.com/lksky8/sign-ql
最后更新日期2025-10-26
食用方法打开捷停车app抓请求url=https://sytgate.jslife.com.cn/core-gateway/user/login/verify/token里面的deviceId和token(一般在请求参数里面)在环境变量输入export jtc_token=账号1#deviceId#token1&账号2#deviceId#token2
支持多用户运行
多用户用&或者@隔开
例如账号1账号1#C5A59624-6666-4682-9876-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9.... 账号2#C5A59624-5555-1234-9E41-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9....
则变量为
export jtc_token="账号1#C5A59624-6666-4682-9876-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9....&账号2#C5A59624-5555-1234-9E41-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9...."
cron: 12 2 * * *
"""
import requests
import time
import hashlib
import os
import re
import uuid
import json
import random
def generate_nonce():
"""生成符合要求的UUID格式字符串"""
return str(uuid.uuid4()).upper()
if 'jtc_token' in os.environ:
jtc_token = re.split("@|&",os.environ.get("jtc_token"))
print(f'查找到{len(jtc_token)}个账号\n')
else:
jtc_token = []
print('无jtc_token变量\n')
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'\n{cont}'
send_msg += f'\n{cont}'
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
api_headers = {
'Host': 'sytgate.jslife.com.cn',
'Content-Type': 'application/json;charset=utf-8',
'applicationVersion': '60406',
'Accept': '*/*',
'User-Agent': 'JTC/6.4.6 (iPhone; iOS 15.8.3; Scale/3.00)',
'Accept-Language': 'zh-Hans-CN;q=1',
}
longitude = f'113.07{random.randint(100, 999)}'
latitude = f'22.888624{random.randint(100, 999)}'
def md5_encrypt(text):
return hashlib.md5(text.encode('utf-8')).hexdigest().upper()
def refresh_token(user_phone,user_deviceid,user_token):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce() # 生成nonce
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&deviceId={user_deviceid}&nonce={nonce}&osType=iOS&signType=MD5&timestamp={timestamp}&token={user_token}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'deviceId': user_deviceid,
'osType': 'iOS',
'signType': 'MD5',
'applictionType': 'APP',
'applictionVersion': '60406',
'token': user_token,
'timestamp': timestamp,
'sign': sign,
'nonce': nonce
}
try:
response = requests.post('https://sytgate.jslife.com.cn/core-gateway/user/login/verify/token',headers=api_headers,json=json_data)
response_json = response.json()
if response_json['resultCode'] == '0' and response_json['message'] == '成功':
print(f'[{user_phone}] 刷新token成功')
return {'new_token': response_json['obj']['token'], 'new_user_id': response_json['obj']['userId']}
elif response_json['resultCode'] == '10011' and response_json['message'] == '用户已在其他平台登录':
print(f'[{user_phone}] 刷新token失败请重新获取token')
elif response_json['resultCode'] == '3126' and response_json['message'] == 'token已过期':
print(f'[{user_phone}] 刷新token失败token已过期请重新获取')
return None
else:
print(f'[{user_phone}] 刷新token失败{response_json}')
return None
except requests.exceptions.RequestException as e:
print(f'刷新token发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'刷新token发生解析错误: {str(e)}')
except Exception as e:
print(f'刷新token发生未知错误: {str(e)}')
def get_coin(token,user_id,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce() # 生成nonce
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&reqSource=APP_JTC&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'userId': user_id,
'signType': 'MD5',
'reqSource': 'APP_JTC',
'applictionType': 'APP',
'applictionVersion': '60406',
'token': token,
'timestamp': timestamp,
'sign': sign,
'nonce': nonce,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/balance/query', headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
print(f'[{user_mobile}] 积分:{response_json["data"]["accountAmt"]},可抵扣:{response_json["data"]["deductAmount"]}')
Log(f'[{user_mobile}] 积分:{response_json["data"]["accountAmt"]},可抵扣:{response_json["data"]["deductAmount"]}')
else:
print(f'[{user_mobile}] 查询积分失败:{response_json["message"]}')
Log(f'[{user_mobile}] 查询积分失败:{response_json["message"]}')
except requests.exceptions.RequestException as e:
print(f'查询用户积分发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询用户积分发生解析错误: {str(e)}')
except Exception as e:
print(f'查询用户积分发生未知错误: {str(e)}')
def get_userinfo(token,user_id):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce() # 生成nonce
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&reqSource=APP_JTC&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'userId': user_id,
'signType': 'MD5',
'sign': sign,
'charset': 'UTF-8',
'reqSource': 'APP_JTC',
'applictionType': 'APP',
'version': 'V1.0',
'token': token,
'timestamp': timestamp,
'applictionVersion': '60406',
'nonce': nonce,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/member/queryUserBenefitInfo',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
if response_json['data']['mobile'] is None:
return None
else:
return response_json['data']['mobile']
else:
print(f'查询用户信息失败:{response_json["message"]}')
return None
except requests.exceptions.RequestException as e:
print(f'查询用户信息发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询用户信息发生解析错误: {str(e)}')
except Exception as e:
print(f'查询用户信息发生未知错误: {str(e)}')
def do_userinfo(user_id,user_mobile):
timestamp = str(int(time.time() * 1000))
json_data = {
'userId': user_id,
'openId': '',
'gender': 'MALE',
'birthday': '2000-01-01',
'province': '广东省',
'city': '广州市',
'platformType': 'APP_JTC',
}
try:
response = requests.post(f'https://sytgate.jslife.com.cn/core-gateway/user/update/extend-info?t={timestamp}',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['resultCode'] == '0':
print(f'[{user_mobile}] 更新用户信息成功:{user_id}')
if response_json['obj']:
print(f'[{user_mobile}] 个人信息已完善并获得30停车币')
except requests.exceptions.RequestException as e:
print(f'更新用户信息发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'更新用户信息发生解析错误: {str(e)}')
except Exception as e:
print(f'更新用户信息发生未知错误: {str(e)}')
def query_task(user_token, user_id, user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&reqSource=APP_JTC&signType=MD5&timestamp={timestamp}&token={user_token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'osType': 'IOS',
'signType': 'MD5',
'userId': user_id,
'nonce': nonce,
'applictionType': 'APP',
'reqVersion': 'V2.0',
'applictionVersion': '60406',
'token': user_token,
'timestamp': timestamp,
'sign': sign,
'platformType': 'APP',
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/task/query',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
daily_tasks = [item for item in response_json['data'] if item["taskType"] == "每日任务"]
task_list = daily_tasks[0]['taskList']
all_tasks = []
for task_item in task_list:
task_id = task_item['taskNo']
task_name = task_item['showTitle']
all_tasks.append({
'task_id': task_id,
'task_name': task_name
})
print(f'[{user_mobile}] 查询任务成功: 已获取到 {len(task_list)} 个任务')
return all_tasks
else:
print(f'查询任务失败:{response_json["message"]}')
return None
except requests.exceptions.RequestException as e:
print(f'查询任务发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询任务发生解析错误: {str(e)}')
except Exception as e:
print(f'查询任务发生未知错误: {str(e)}')
def do_task(token,user_id,task_id,task_name,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&osType=IOS&platformType=APP&receiveTag=false&reqSource=APP_JTC&signType=MD5&taskNo={task_id}&timestamp={timestamp}&token={token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'nonce': nonce,
'taskNo': task_id,
'reqSource': 'APP_JTC',
'receiveTag': 'false',
'applictionVersion': '60406',
'timestamp': timestamp,
'osType': 'IOS',
'userId': user_id,
'applictionType': 'APP',
'token': token,
'platformType': 'APP',
'signType': 'MD5',
'sign': sign,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/task/complete',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
print(f'[{user_mobile}]【{task_name}】 任务成功,获得 {response_json["data"]["integralValue"]} 停车币')
elif response_json['code'] == '1' or response_json['code'] == 'INTER006':
print(f'[{user_mobile}]【{task_name}】 任务失败: {response_json["message"]}')
else:
print(f'[{user_mobile}]【{task_name}】 任务未知错误')
print(response_json)
except requests.exceptions.RequestException as e:
print(f'完成任务发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'完成任务发生解析错误: {str(e)}')
except Exception as e:
print(f'完成任务发生未知错误: {str(e)}')
def task_report(deviceId,user_id,token,user_mobile):
timestamp = str(int(time.time() * 1000))
event = '{"referrer":"PersonalCenterPage","pageEventName":"PointsTaskPage"}'
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&dataSourceType=原生&deviceId={deviceId}&eventName=MoreTaskClick&eventProperty={event}&eventType=activity&latitude={latitude}&longitude={longitude}&netType=NET_WIFI&nonce={nonce}&opSystem=iOS&opSystemVersion=14.6&phoneModel=iPhone10,3&productName=捷停车APP&productVersion=6.4.6&screenResolution=375*812&serviceProviders=未知&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&GaT92Kf6cbDc1Pea9S720GJnL56A14x3R')
json_data = {
'dataSourceType': '原生',
'eventType': 'activity',
'opSystem': 'iOS',
'deviceId': deviceId,
'opSystemVersion': '14.6',
'phoneModel': 'iPhone10,3',
'latitude': latitude,
'eventName': 'MoreTaskClick',
'netType': 'NET_WIFI',
'signType': 'MD5',
'nonce': nonce,
'sign': sign,
'token': token,
'timestamp': timestamp,
'eventProperty': {
'referrer': 'PersonalCenterPage',
'pageEventName': 'PointsTaskPage',
},
'longitude': longitude,
'serviceProviders': '未知',
'applictionVersion': '60406',
'screenResolution': '375*812',
'productName': '捷停车APP',
'applictionType': 'APP',
'productVersion': '6.4.6',
'userId': user_id,
}
response = requests.post('https://sytgate.jslife.com.cn/data-report-gateway/syt-data-report/receive',headers=api_headers,json=json_data)
if response.json()['resultCode'] == '0' and response.json()['success'] :
print(f'[{user_mobile}] 任务数据上报成功')
else:
print(f'[{user_mobile}] 任务数据上报失败')
def task_report2(deviceId,user_id,user_token,task_name,user_mobile):
nonce = generate_nonce()
timestamp = str(int(time.time() * 1000))
event = json.dumps({"referrer":"PersonalCenterPage","pageEventName":"PointsTaskPage","TaskName":task_name}, separators=(',', ':'))
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&dataSourceType=原生&deviceId={deviceId}&eventName=ShowGoToFinish&eventProperty={event}&eventType=activity&latitude={latitude}&longitude={longitude}&netType=NET_WIFI&nonce={nonce}&opSystem=iOS&opSystemVersion=14.6&phoneModel=iPhone10,3&productName=捷停车APP&productVersion=6.4.6&screenResolution=375*812&serviceProviders=未知&signType=MD5&timestamp={timestamp}&token={user_token}&userId={user_id}&GaT92Kf6cbDc1Pea9S720GJnL56A14x3R')
json_data = {
'dataSourceType': '原生',
'eventType': 'activity',
'opSystem': 'iOS',
'deviceId': deviceId,
'opSystemVersion': '14.6',
'phoneModel': 'iPhone10,3',
'latitude': latitude,
'eventName': 'ShowGoToFinish',
'netType': 'NET_WIFI',
'signType': 'MD5',
'nonce': nonce,
'sign': sign,
'token': user_token,
'timestamp': timestamp,
'eventProperty': {
'referrer': 'PointsDetailPage',
'pageEventName': 'PointsTaskPage',
'TaskName': task_name,
},
'longitude': longitude,
'serviceProviders': '未知',
'applictionVersion': '60408',
'screenResolution': '375*812',
'productName': '捷停车APP',
'applictionType': 'APP',
'productVersion': '6.4.8',
'userId': user_id,
}
response = requests.post('https://sytgate.jslife.com.cn/data-report-gateway/syt-data-report/receive',headers=api_headers,json=json_data)
if response.json()['resultCode'] == '0' and response.json()['success'] :
print(f'[{user_mobile}] 数据上报成功')
else:
print(f'[{user_mobile}] 数据上报失败')
def find_report(deviceId,user_id,token,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
event = json.dumps({"referrer":"PointsTaskPage","pageEventName":"FindPreferentialPage"}, separators=(',', ':'))
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&dataSourceType=原生&deviceId={deviceId}&eventName=ShowGoToClaim&eventProperty={event}&eventType=activity&latitude={latitude}&longitude={longitude}&netType=NET_WIFI&nonce={nonce}&opSystem=iOS&opSystemVersion=14.6&phoneModel=iPhone10,3&productName=捷停车APP&productVersion=6.4.6&screenResolution=375*812&serviceProviders=未知&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&GaT92Kf6cbDc1Pea9S720GJnL56A14x3R')
json_data = {
'dataSourceType': '原生',
'eventType': 'activity',
'opSystem': 'iOS',
'deviceId': deviceId,
'opSystemVersion': '14.6',
'phoneModel': 'iPhone10,3',
'latitude': latitude,
'eventName': 'ShowGoToClaim',
'netType': 'NET_WIFI',
'signType': 'MD5',
'nonce': nonce,
'sign': sign,
'token': token,
'timestamp': timestamp,
'eventProperty': {
'referrer': 'PointsTaskPage',
'pageEventName': 'FindPreferentialPage',
},
'longitude': longitude,
'serviceProviders': '未知',
'applictionVersion': '60406',
'screenResolution': '375*812',
'productName': '捷停车APP',
'applictionType': 'APP',
'productVersion': '6.4.6',
'userId': user_id,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/data-report-gateway/syt-data-report/receive',headers=api_headers,json=json_data)
if response.json()['resultCode'] == '0' and response.json()['success'] :
print(f'[{user_mobile}]【去找优惠】任务数据上报成功')
else:
print(f'{[user_mobile]}【去找优惠】任务数据上报失败')
except requests.exceptions.RequestException as e:
print(f'【去找优惠】任务数据上报发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'【去找优惠】任务数据上报发生解析错误: {str(e)}')
except Exception as e:
print(f'【去找优惠】任务数据上报发生未知错误: {str(e)}')
def query_day_sign(token, userid,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&signType=MD5&timestamp={timestamp}&token={token}&userId={userid}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'userId': userid,
'signType': 'MD5',
'applictionType': 'APP',
'applictionVersion': '60406',
'token': token,
'timestamp': timestamp,
'sign': sign,
'nonce': nonce,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/sign-in-task/query', headers=api_headers,json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
# print(f'[{user_mobile}] 每日签到查询成功')
if not response_json['data']['todaySingInTag']:
print(f'[{user_mobile}] 每日签到未完成')
task_receive(token,userid,response_json['data']['taskNo'],'每日签到',user_mobile)
else:
print(f'[{user_mobile}] 每日签到已完成')
Log(f'[{user_mobile}] 每日签到已完成')
else:
print(f'[{user_mobile}] 每日签到查询失败:{response_json["message"]}')
except requests.exceptions.RequestException as e:
print(f'查询每日签到发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询每日签到发生解析错误: {str(e)}')
except Exception as e:
print(f'查询每日签到发生未知错误: {str(e)}')
def task_receive(token,userid,task_id,task_name,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&osType=IOS&platformType=APP&reqSource=APP_JTC&signType=MD5&taskNo={task_id}&timestamp={timestamp}&token={token}&userId={userid}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'nonce': nonce,
'taskNo': task_id,
'reqSource': 'APP_JTC',
'applictionVersion': '60406',
'timestamp': timestamp,
'osType': 'IOS',
'userId': userid,
'applictionType': 'APP',
'token': token,
'platformType': 'APP',
'signType': 'MD5',
'sign': sign,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/task/receive', headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
print(f'[{user_mobile}]【{task_name}】 获得 {response_json["data"]} 停车币')
Log(f'[{user_mobile}]【{task_name}】 获得 {response_json["data"]} 停车币')
else:
print(f'[{user_mobile}]【{task_name}】 领取任务奖励失败:{response_json["message"]}')
except requests.exceptions.RequestException as e:
print(f'领取任务奖励发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'领取任务奖励发生解析错误: {str(e)}')
except Exception as e:
print(f'领取任务奖励发生未知错误: {str(e)}')
if __name__ == '__main__':
try:
if jtc_token:
z = 1
for item in jtc_token:
print('-' * 50)
print(f'登录第{z}个账号>>>>>>')
phone = item.split('#')[0]
device_id = item.split('#')[1]
token = item.split('#')[2]
user_data = refresh_token(phone, device_id, token)
if user_data:
new_userid = user_data['new_user_id']
new_token = user_data['new_token']
query_day_sign(new_token, new_userid, phone)
print('-' * 50)
task_report(device_id, new_userid, new_token, phone)
tasks = query_task(new_token, new_userid, phone)
if tasks:
for task in tasks:
task_report2(device_id, new_userid, new_token, task['task_name'], phone)
if task['task_name'] == '看视频':
print(f'[{phone}]【看视频】跳过任务')
# 破解不了直接跳过
continue
if task['task_name'] == '去找优惠':
find_report(device_id, new_userid, new_token, phone)
time.sleep(5)
do_task(new_token, new_userid, task['task_id'], task['task_name'], phone)
time.sleep(3)
task_receive(new_token, new_userid, task['task_id'], task['task_name'], phone)
time.sleep(2)
# do_userinfo(userid, user_phone)
print('-' * 50)
get_coin(new_token, new_userid, phone)
print('*' * 50)
Log('\n')
else:
print(f'{z}个账号用户信息获取失败')
Log(f'{z}个账号用户信息获取失败')
z += 1
else:
print('请先填入jtc_token变量')
Log('请先填入jtc_token变量')
except Exception as e:
print(f'发生错误: {str(e)}')
try:
send_notification_message(title='捷停车') # 发送通知
except Exception as e:
print('推送失败:' + str(e))

View File

@@ -0,0 +1,540 @@
# Source: https://github.com/lksky8/sign-ql/blob/main/jtc.py
# Raw: https://raw.githubusercontent.com/lksky8/sign-ql/main/jtc.py
# Repo: lksky8/sign-ql
# Path: jtc.py
# UploadedAt: 2025-10-26T12:24:47Z
# SHA256: d7fa5acdc107ddb45fd772c4bb0c9491fd48e8e3d7d18ae5a4286579151676ef
# Category: 微信小程序/抓包版
# Evidence: appid/openid/session_key/encryptedData等小程序字段
"""
捷停车签到
作者https://github.com/lksky8/sign-ql
最后更新日期2025-10-26
食用方法打开捷停车app抓请求url=https://sytgate.jslife.com.cn/core-gateway/user/login/verify/token里面的deviceId和token(一般在请求参数里面)在环境变量输入export jtc_token=账号1#deviceId#token1&账号2#deviceId#token2
支持多用户运行
多用户用&或者@隔开
例如账号1账号1#C5A59624-6666-4682-9876-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9.... 账号2#C5A59624-5555-1234-9E41-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9....
则变量为
export jtc_token="账号1#C5A59624-6666-4682-9876-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9....&账号2#C5A59624-5555-1234-9E41-F8184F3D2CF0#eyJhbGciOiJIUzI1NiJ9...."
cron: 12 2 * * *
"""
import requests
import time
import hashlib
import os
import re
import uuid
import json
import random
def generate_nonce():
"""生成符合要求的UUID格式字符串"""
return str(uuid.uuid4()).upper()
if 'jtc_token' in os.environ:
jtc_token = re.split("@|&",os.environ.get("jtc_token"))
print(f'查找到{len(jtc_token)}个账号\n')
else:
jtc_token = []
print('无jtc_token变量\n')
send_msg = ''
one_msg = ''
def Log(cont=''):
global send_msg, one_msg
if cont:
one_msg += f'\n{cont}'
send_msg += f'\n{cont}'
def send_notification_message(title):
try:
from notify import send
print("加载通知服务成功!")
send(title, send_msg)
except Exception as e:
if e:
print('发送通知消息失败!')
api_headers = {
'Host': 'sytgate.jslife.com.cn',
'Content-Type': 'application/json;charset=utf-8',
'applicationVersion': '60406',
'Accept': '*/*',
'User-Agent': 'JTC/6.4.6 (iPhone; iOS 15.8.3; Scale/3.00)',
'Accept-Language': 'zh-Hans-CN;q=1',
}
longitude = f'113.07{random.randint(100, 999)}'
latitude = f'22.888624{random.randint(100, 999)}'
def md5_encrypt(text):
return hashlib.md5(text.encode('utf-8')).hexdigest().upper()
def refresh_token(user_phone,user_deviceid,user_token):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce() # 生成nonce
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&deviceId={user_deviceid}&nonce={nonce}&osType=iOS&signType=MD5&timestamp={timestamp}&token={user_token}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'deviceId': user_deviceid,
'osType': 'iOS',
'signType': 'MD5',
'applictionType': 'APP',
'applictionVersion': '60406',
'token': user_token,
'timestamp': timestamp,
'sign': sign,
'nonce': nonce
}
try:
response = requests.post('https://sytgate.jslife.com.cn/core-gateway/user/login/verify/token',headers=api_headers,json=json_data)
response_json = response.json()
if response_json['resultCode'] == '0' and response_json['message'] == '成功':
print(f'[{user_phone}] 刷新token成功')
return {'new_token': response_json['obj']['token'], 'new_user_id': response_json['obj']['userId']}
elif response_json['resultCode'] == '10011' and response_json['message'] == '用户已在其他平台登录':
print(f'[{user_phone}] 刷新token失败请重新获取token')
elif response_json['resultCode'] == '3126' and response_json['message'] == 'token已过期':
print(f'[{user_phone}] 刷新token失败token已过期请重新获取')
return None
else:
print(f'[{user_phone}] 刷新token失败{response_json}')
return None
except requests.exceptions.RequestException as e:
print(f'刷新token发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'刷新token发生解析错误: {str(e)}')
except Exception as e:
print(f'刷新token发生未知错误: {str(e)}')
def get_coin(token,user_id,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce() # 生成nonce
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&reqSource=APP_JTC&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'userId': user_id,
'signType': 'MD5',
'reqSource': 'APP_JTC',
'applictionType': 'APP',
'applictionVersion': '60406',
'token': token,
'timestamp': timestamp,
'sign': sign,
'nonce': nonce,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/balance/query', headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
print(f'[{user_mobile}] 积分:{response_json["data"]["accountAmt"]},可抵扣:{response_json["data"]["deductAmount"]}')
Log(f'[{user_mobile}] 积分:{response_json["data"]["accountAmt"]},可抵扣:{response_json["data"]["deductAmount"]}')
else:
print(f'[{user_mobile}] 查询积分失败:{response_json["message"]}')
Log(f'[{user_mobile}] 查询积分失败:{response_json["message"]}')
except requests.exceptions.RequestException as e:
print(f'查询用户积分发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询用户积分发生解析错误: {str(e)}')
except Exception as e:
print(f'查询用户积分发生未知错误: {str(e)}')
def get_userinfo(token,user_id):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce() # 生成nonce
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&reqSource=APP_JTC&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'userId': user_id,
'signType': 'MD5',
'sign': sign,
'charset': 'UTF-8',
'reqSource': 'APP_JTC',
'applictionType': 'APP',
'version': 'V1.0',
'token': token,
'timestamp': timestamp,
'applictionVersion': '60406',
'nonce': nonce,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/member/queryUserBenefitInfo',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
if response_json['data']['mobile'] is None:
return None
else:
return response_json['data']['mobile']
else:
print(f'查询用户信息失败:{response_json["message"]}')
return None
except requests.exceptions.RequestException as e:
print(f'查询用户信息发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询用户信息发生解析错误: {str(e)}')
except Exception as e:
print(f'查询用户信息发生未知错误: {str(e)}')
def do_userinfo(user_id,user_mobile):
timestamp = str(int(time.time() * 1000))
json_data = {
'userId': user_id,
'openId': '',
'gender': 'MALE',
'birthday': '2000-01-01',
'province': '广东省',
'city': '广州市',
'platformType': 'APP_JTC',
}
try:
response = requests.post(f'https://sytgate.jslife.com.cn/core-gateway/user/update/extend-info?t={timestamp}',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['resultCode'] == '0':
print(f'[{user_mobile}] 更新用户信息成功:{user_id}')
if response_json['obj']:
print(f'[{user_mobile}] 个人信息已完善并获得30停车币')
except requests.exceptions.RequestException as e:
print(f'更新用户信息发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'更新用户信息发生解析错误: {str(e)}')
except Exception as e:
print(f'更新用户信息发生未知错误: {str(e)}')
def query_task(user_token, user_id, user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&reqSource=APP_JTC&signType=MD5&timestamp={timestamp}&token={user_token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'osType': 'IOS',
'signType': 'MD5',
'userId': user_id,
'nonce': nonce,
'applictionType': 'APP',
'reqVersion': 'V2.0',
'applictionVersion': '60406',
'token': user_token,
'timestamp': timestamp,
'sign': sign,
'platformType': 'APP',
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/task/query',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
daily_tasks = [item for item in response_json['data'] if item["taskType"] == "每日任务"]
task_list = daily_tasks[0]['taskList']
all_tasks = []
for task_item in task_list:
task_id = task_item['taskNo']
task_name = task_item['showTitle']
all_tasks.append({
'task_id': task_id,
'task_name': task_name
})
print(f'[{user_mobile}] 查询任务成功: 已获取到 {len(task_list)} 个任务')
return all_tasks
else:
print(f'查询任务失败:{response_json["message"]}')
return None
except requests.exceptions.RequestException as e:
print(f'查询任务发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询任务发生解析错误: {str(e)}')
except Exception as e:
print(f'查询任务发生未知错误: {str(e)}')
def do_task(token,user_id,task_id,task_name,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&osType=IOS&platformType=APP&receiveTag=false&reqSource=APP_JTC&signType=MD5&taskNo={task_id}&timestamp={timestamp}&token={token}&userId={user_id}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'nonce': nonce,
'taskNo': task_id,
'reqSource': 'APP_JTC',
'receiveTag': 'false',
'applictionVersion': '60406',
'timestamp': timestamp,
'osType': 'IOS',
'userId': user_id,
'applictionType': 'APP',
'token': token,
'platformType': 'APP',
'signType': 'MD5',
'sign': sign,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/task/complete',headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
print(f'[{user_mobile}]【{task_name}】 任务成功,获得 {response_json["data"]["integralValue"]} 停车币')
elif response_json['code'] == '1' or response_json['code'] == 'INTER006':
print(f'[{user_mobile}]【{task_name}】 任务失败: {response_json["message"]}')
else:
print(f'[{user_mobile}]【{task_name}】 任务未知错误')
print(response_json)
except requests.exceptions.RequestException as e:
print(f'完成任务发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'完成任务发生解析错误: {str(e)}')
except Exception as e:
print(f'完成任务发生未知错误: {str(e)}')
def task_report(deviceId,user_id,token,user_mobile):
timestamp = str(int(time.time() * 1000))
event = '{"referrer":"PersonalCenterPage","pageEventName":"PointsTaskPage"}'
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&dataSourceType=原生&deviceId={deviceId}&eventName=MoreTaskClick&eventProperty={event}&eventType=activity&latitude={latitude}&longitude={longitude}&netType=NET_WIFI&nonce={nonce}&opSystem=iOS&opSystemVersion=14.6&phoneModel=iPhone10,3&productName=捷停车APP&productVersion=6.4.6&screenResolution=375*812&serviceProviders=未知&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&GaT92Kf6cbDc1Pea9S720GJnL56A14x3R')
json_data = {
'dataSourceType': '原生',
'eventType': 'activity',
'opSystem': 'iOS',
'deviceId': deviceId,
'opSystemVersion': '14.6',
'phoneModel': 'iPhone10,3',
'latitude': latitude,
'eventName': 'MoreTaskClick',
'netType': 'NET_WIFI',
'signType': 'MD5',
'nonce': nonce,
'sign': sign,
'token': token,
'timestamp': timestamp,
'eventProperty': {
'referrer': 'PersonalCenterPage',
'pageEventName': 'PointsTaskPage',
},
'longitude': longitude,
'serviceProviders': '未知',
'applictionVersion': '60406',
'screenResolution': '375*812',
'productName': '捷停车APP',
'applictionType': 'APP',
'productVersion': '6.4.6',
'userId': user_id,
}
response = requests.post('https://sytgate.jslife.com.cn/data-report-gateway/syt-data-report/receive',headers=api_headers,json=json_data)
if response.json()['resultCode'] == '0' and response.json()['success'] :
print(f'[{user_mobile}] 任务数据上报成功')
else:
print(f'[{user_mobile}] 任务数据上报失败')
def task_report2(deviceId,user_id,user_token,task_name,user_mobile):
nonce = generate_nonce()
timestamp = str(int(time.time() * 1000))
event = json.dumps({"referrer":"PersonalCenterPage","pageEventName":"PointsTaskPage","TaskName":task_name}, separators=(',', ':'))
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&dataSourceType=原生&deviceId={deviceId}&eventName=ShowGoToFinish&eventProperty={event}&eventType=activity&latitude={latitude}&longitude={longitude}&netType=NET_WIFI&nonce={nonce}&opSystem=iOS&opSystemVersion=14.6&phoneModel=iPhone10,3&productName=捷停车APP&productVersion=6.4.6&screenResolution=375*812&serviceProviders=未知&signType=MD5&timestamp={timestamp}&token={user_token}&userId={user_id}&GaT92Kf6cbDc1Pea9S720GJnL56A14x3R')
json_data = {
'dataSourceType': '原生',
'eventType': 'activity',
'opSystem': 'iOS',
'deviceId': deviceId,
'opSystemVersion': '14.6',
'phoneModel': 'iPhone10,3',
'latitude': latitude,
'eventName': 'ShowGoToFinish',
'netType': 'NET_WIFI',
'signType': 'MD5',
'nonce': nonce,
'sign': sign,
'token': user_token,
'timestamp': timestamp,
'eventProperty': {
'referrer': 'PointsDetailPage',
'pageEventName': 'PointsTaskPage',
'TaskName': task_name,
},
'longitude': longitude,
'serviceProviders': '未知',
'applictionVersion': '60408',
'screenResolution': '375*812',
'productName': '捷停车APP',
'applictionType': 'APP',
'productVersion': '6.4.8',
'userId': user_id,
}
response = requests.post('https://sytgate.jslife.com.cn/data-report-gateway/syt-data-report/receive',headers=api_headers,json=json_data)
if response.json()['resultCode'] == '0' and response.json()['success'] :
print(f'[{user_mobile}] 数据上报成功')
else:
print(f'[{user_mobile}] 数据上报失败')
def find_report(deviceId,user_id,token,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
event = json.dumps({"referrer":"PointsTaskPage","pageEventName":"FindPreferentialPage"}, separators=(',', ':'))
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&dataSourceType=原生&deviceId={deviceId}&eventName=ShowGoToClaim&eventProperty={event}&eventType=activity&latitude={latitude}&longitude={longitude}&netType=NET_WIFI&nonce={nonce}&opSystem=iOS&opSystemVersion=14.6&phoneModel=iPhone10,3&productName=捷停车APP&productVersion=6.4.6&screenResolution=375*812&serviceProviders=未知&signType=MD5&timestamp={timestamp}&token={token}&userId={user_id}&GaT92Kf6cbDc1Pea9S720GJnL56A14x3R')
json_data = {
'dataSourceType': '原生',
'eventType': 'activity',
'opSystem': 'iOS',
'deviceId': deviceId,
'opSystemVersion': '14.6',
'phoneModel': 'iPhone10,3',
'latitude': latitude,
'eventName': 'ShowGoToClaim',
'netType': 'NET_WIFI',
'signType': 'MD5',
'nonce': nonce,
'sign': sign,
'token': token,
'timestamp': timestamp,
'eventProperty': {
'referrer': 'PointsTaskPage',
'pageEventName': 'FindPreferentialPage',
},
'longitude': longitude,
'serviceProviders': '未知',
'applictionVersion': '60406',
'screenResolution': '375*812',
'productName': '捷停车APP',
'applictionType': 'APP',
'productVersion': '6.4.6',
'userId': user_id,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/data-report-gateway/syt-data-report/receive',headers=api_headers,json=json_data)
if response.json()['resultCode'] == '0' and response.json()['success'] :
print(f'[{user_mobile}]【去找优惠】任务数据上报成功')
else:
print(f'{[user_mobile]}【去找优惠】任务数据上报失败')
except requests.exceptions.RequestException as e:
print(f'【去找优惠】任务数据上报发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'【去找优惠】任务数据上报发生解析错误: {str(e)}')
except Exception as e:
print(f'【去找优惠】任务数据上报发生未知错误: {str(e)}')
def query_day_sign(token, userid,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&signType=MD5&timestamp={timestamp}&token={token}&userId={userid}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'userId': userid,
'signType': 'MD5',
'applictionType': 'APP',
'applictionVersion': '60406',
'token': token,
'timestamp': timestamp,
'sign': sign,
'nonce': nonce,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/sign-in-task/query', headers=api_headers,json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
# print(f'[{user_mobile}] 每日签到查询成功')
if not response_json['data']['todaySingInTag']:
print(f'[{user_mobile}] 每日签到未完成')
task_receive(token,userid,response_json['data']['taskNo'],'每日签到',user_mobile)
else:
print(f'[{user_mobile}] 每日签到已完成')
Log(f'[{user_mobile}] 每日签到已完成')
else:
print(f'[{user_mobile}] 每日签到查询失败:{response_json["message"]}')
except requests.exceptions.RequestException as e:
print(f'查询每日签到发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'查询每日签到发生解析错误: {str(e)}')
except Exception as e:
print(f'查询每日签到发生未知错误: {str(e)}')
def task_receive(token,userid,task_id,task_name,user_mobile):
timestamp = str(int(time.time() * 1000))
nonce = generate_nonce()
sign = md5_encrypt(f'applictionType=APP&applictionVersion=60406&nonce={nonce}&osType=IOS&platformType=APP&reqSource=APP_JTC&signType=MD5&taskNo={task_id}&timestamp={timestamp}&token={token}&userId={userid}&Uvn76f3KgH9jlO9pCxZA12Swr5TeYQ8d')
json_data = {
'nonce': nonce,
'taskNo': task_id,
'reqSource': 'APP_JTC',
'applictionVersion': '60406',
'timestamp': timestamp,
'osType': 'IOS',
'userId': userid,
'applictionType': 'APP',
'token': token,
'platformType': 'APP',
'signType': 'MD5',
'sign': sign,
}
try:
response = requests.post('https://sytgate.jslife.com.cn/base-gateway/integral/v2/task/receive', headers=api_headers, json=json_data)
response_json = response.json()
if response_json['code'] == '0' and response_json['success']:
print(f'[{user_mobile}]【{task_name}】 获得 {response_json["data"]} 停车币')
Log(f'[{user_mobile}]【{task_name}】 获得 {response_json["data"]} 停车币')
else:
print(f'[{user_mobile}]【{task_name}】 领取任务奖励失败:{response_json["message"]}')
except requests.exceptions.RequestException as e:
print(f'领取任务奖励发生网络错误: {str(e)}')
except (ValueError, KeyError, TypeError) as e:
print(f'领取任务奖励发生解析错误: {str(e)}')
except Exception as e:
print(f'领取任务奖励发生未知错误: {str(e)}')
if __name__ == '__main__':
try:
if jtc_token:
z = 1
for item in jtc_token:
print('-' * 50)
print(f'登录第{z}个账号>>>>>>')
phone = item.split('#')[0]
device_id = item.split('#')[1]
token = item.split('#')[2]
user_data = refresh_token(phone, device_id, token)
if user_data:
new_userid = user_data['new_user_id']
new_token = user_data['new_token']
query_day_sign(new_token, new_userid, phone)
print('-' * 50)
task_report(device_id, new_userid, new_token, phone)
tasks = query_task(new_token, new_userid, phone)
if tasks:
for task in tasks:
task_report2(device_id, new_userid, new_token, task['task_name'], phone)
if task['task_name'] == '看视频':
print(f'[{phone}]【看视频】跳过任务')
# 破解不了直接跳过
continue
if task['task_name'] == '去找优惠':
find_report(device_id, new_userid, new_token, phone)
time.sleep(5)
do_task(new_token, new_userid, task['task_id'], task['task_name'], phone)
time.sleep(3)
task_receive(new_token, new_userid, task['task_id'], task['task_name'], phone)
time.sleep(2)
# do_userinfo(userid, user_phone)
print('-' * 50)
get_coin(new_token, new_userid, phone)
print('*' * 50)
Log('\n')
else:
print(f'{z}个账号用户信息获取失败')
Log(f'{z}个账号用户信息获取失败')
z += 1
else:
print('请先填入jtc_token变量')
Log('请先填入jtc_token变量')
except Exception as e:
print(f'发生错误: {str(e)}')
try:
send_notification_message(title='捷停车') # 发送通知
except Exception as e:
print('推送失败:' + str(e))

View File

@@ -0,0 +1,793 @@
// # Source: https://github.com/DearSong15/ql-scripts/blob/main/ks_dual.js
// # Raw: https://raw.githubusercontent.com/DearSong15/ql-scripts/main/ks_dual.js
// # Repo: DearSong15/ql-scripts
// # Path: ks_dual.js
// # UploadedAt: 2026-05-11T15:03:30Z
// # SHA256: aa4fbaa74f4c00599fa2a8c1e358c99c6f393dc9b180b7c8260162ddd20b1e0f
// # Category: 微信小程序/抓包版
// # Evidence: appid/openid/session_key/encryptedData等小程序字段
//
//new Env("快手双端")
const axios = require("axios");
const querystring = require("querystring");
const { SocksProxyAgent } = require("socks-proxy-agent");
const dns = require("dns");
dns.setDefaultResultOrder("ipv4first");
dns.setServers(["8.8.8.8", "114.114.114.114", "223.5.5.5"]);
// ==============================================
// 自定义签名接口KUAISHOU=81端口 NEBULA=82端口
// ==============================================
const SIGN_API_KUAISHOU = "http://127.0.0.1:81"; // 普通版(kpn=KUAISHOU)
const SIGN_API_NEBULA = "http://127.0.0.1:82"; // 极速版(kpn=NEBULA)
console.log("💡 普通版签名API: " + SIGN_API_KUAISHOU);
console.log("💡 极速版签名API: " + SIGN_API_NEBULA);
// 全局配置(原配置未改动)
const CONFIG = {
SEARCH_KEYWORDS: process.env.KS_SEARCH_KEYWORDS?.split(",") || ["短剧小说", "热门视频", "美食教程"],
DEFAULT_TASKS: process.env.KS_DEFAULT_TASKS?.split(",") || ["box", "look", "food", "search"],
CYCLE_ROUNDS: parseInt(process.env.KS_CYCLE_ROUNDS || 0),
WATCH_MIN: parseInt(process.env.KS_WATCH_MIN || 30),
WATCH_MAX: parseInt(process.env.KS_WATCH_MAX || 40),
AD_FAIL_LIMIT: parseInt(process.env.KS_AD_FAIL_LIMIT || 10),
CONTINUOUS_1COIN_LIMIT: parseInt(process.env.KS_CONTINUOUS_1COIN_LIMIT || 3),
APPEND_REST_INTERVAL: parseInt(process.env.KS_APPEND_INTERVAL || 5),
APPEND_REST_MIN: parseInt(process.env.KS_APPEND_MIN || 5000),
APPEND_REST_MAX: parseInt(process.env.KS_APPEND_MAX || 10000),
LOW_REWARD_THRESHOLD: parseInt(process.env.KS_LOW_REWARD_THRESHOLD || 10),
LOW_REWARD_LIMIT: parseInt(process.env.KS_LOW_REWARD_LIMIT || 3),
PLATFORM_CONFIG: {
KUAISHOU: {
name: "KS",
accountInfoUrl: "https://encourage.kuaishou.com/rest/wd/encourage/account/basicInfo",
host: "encourage.kuaishou.com",
appId: "kuaishou",
packageName: "com.smile.gifmaker",
appName: "快手",
displayName: "快手",
kpn: "KUAISHOU",
adClientKey: "3c2cd3f3",
reportClientKey: "3c2cd3f3"
},
NEBULA: {
name: "JSB",
accountInfoUrl: "https://nebula.kuaishou.com/rest/n/nebula/activity/earn/overview/basicInfo",
host: "nebula.kuaishou.com",
appId: "kuaishou_nebula",
packageName: "com.kuaishou.nebula",
appName: "快手极速版",
displayName: "快手极速版",
kpn: "NEBULA",
adClientKey: "2ac2a76d",
reportClientKey: "2ac2a76d"
}
},
TASK_CONFIGS: {
KUAISHOU: {
box: {
name: "宝箱广告",
businessId: 604, posId: 20345, subPageId: 100024063,
requestSceneType: 1, taskType: 1, pageId: 100011251
},
look: {
name: "看广告得金币",
businessId: 671, posId: 24068, subPageId: 100026368,
requestSceneType: 1, taskType: 1, pageId: 100011251
},
food: {
name: "饭补广告",
businessId: 921, posId: 29742, subPageId: 100029908,
requestSceneType: 7, taskType: 2, pageId: 100011251
},
search: {
name: "搜索广告",
businessId: 7077, posId: 216267, subPageId: 100161535,
pageId: 10014, requestSceneType: 1, taskType: 2,
linkUrl: "eyJwYWdlSWQiOjEwMDE0LCJzdWJQYWdlSWQiOjEwMDE2MTUzNSwicG9zSWQiOjIxNjI2NywiYnVzaW5lc3NJZCI6NzA3NywiZXh0UGFyYW1zIjoiYzc4OWI1ZTAzMjMxOTUwZjcyM2ZjMWE1ZGJjYzgwNmYzMDE1OTcyZWE0Mzc2NmNlNDYwNTk2ZDgzMGVjNTE5MDM0OGEwNTlkOTA2NWYwZGY1ZjkwY2YwMjEwMGVhMmQzYzU0YjUyZDBlNGUxY2Q0NmMxN2ExZDU3YmRhY2EyMzVlM2U1NjYzN2JmZGQzMThiZWMzNTgzOWU1YzIxNWUyNzMzY2IyMzQ2ZGQ1NDYyODc1NDdlMjc4OWYxMjZjZWU5NWZhYzg4N2IxMzM2MzBlZTEzYTVmYTlhODYzNDYxODQ5MjM0NDk3ZGY3ZTRmOWYyYzk2ZjQ5YzViMGExNzQ2NGE2MGM0MDg1MzU2NTY2ZDc4NGIxYjY3NzY3MzYzYjg3IiwiY3VzdG9tRGF0YSI6eyJleGl0SW5mbyI6eyJ0b2FzdERlc2MiOm51bGwsInRvYXN0SW1nVXJsIjpudWxsfX0sInBlbmRhbnRUeXBlIjoxLCJkaXNwbGF5VHlwZSI6Miwic2luZ2xlUGFnZUlkIjowLCJzaW5nbGVTdWJQYWdlSWQiOjAsImNoYW5uZWwiOjAsImNvdW50ZG93blJlcG9ydCI6ZmFsc2UsInRoZW1lVHlwZSI6MCwibWl4ZWRBZCI6dHJ1ZSwiZnVsbE1peGVkIjp0cnVlLCJhdXRvUmVwb3J0Ijp0cnVlLCJmcm9tVGFza0NlbnRlciI6dHJ1ZSwic2VhcmNoSW5zcGlyZVNjaGVtZUluZm8iOm51bGwsImFtb3VudCI6MH0="
}
},
NEBULA: {
box: {
name: "宝箱广告",
pageId: 11101, subPageId: 100024064, businessId: 606, posId: 20346,
requestSceneType: 1, taskType: 1
},
look: {
name: "看广告得金币",
pageId: 11101, subPageId: 100026367, businessId: 672, posId: 24067,
requestSceneType: 1, taskType: 1
},
food: {
name: "饭补广告",
pageId: 11101, subPageId: 100026367, businessId: 9362, posId: 24067,
requestSceneType: 7, taskType: 2
},
search: {
name: "搜索广告",
pageId: 11014, subPageId: 100161537, businessId: 7076, posId: 216268,
requestSceneType: 1, taskType: 1,
linkUrl: "eyJwYWdlSWQiOjExMDE0LCJzdWJQYWdlSWQiOjEwMDE2MTUzNywicG9zSWQiOjIxNjI2OCwiYnVzaW5lc3NJZCI6NzA3NiwiZXh0UGFyYW1zIjoiYjc4OWI1ZTAzMjMxOTUwZjcyM2ZjMWE1ZGJjYzgwNmYzMDE1OTcyZWE0Mzc2NmNlNDYwNTk2ZDgzMGVjNTE5MDM0OGEwNTlkOTA2NWYwZGY1ZjkwY2YwMjEwMGVhMmQzYzU0YjUyZDBlNGUxY2Q0NmMxN2ExZDU3YmRhY2EyMzVlM2U1NjYzN2JmZGQzMThiZWMzNTgzOWU1YzIxNWUyNzMzY2IyMzQ2ZGQ1NDYyODc1NDdlMjc4OWYxMjZjZWU5NWZhYzg4N2IxMzM2MzBlZTEzYTVmYTlhODYzNDYxODQ5MjM0NDk3ZGY3ZTRmOWYyYzk2ZjQ5YzViMGExNzQ2NGE2MGM0MDg1MzU2NTY2ZDc4NGIxYjY3NzY3MzYzYjg3IiwiY3VzdG9tRGF0YSI6eyJleGl0SW5mbyI6eyJ0b2FzdERlc2MiOm51bGwsInRvYXN0SW1nVXJsIjpudWxsfX0sInBlbmRhbnRUeXBlIjoxLCJkaXNwbGF5VHlwZSI6Miwic2luZ2xlUGFnZUlkIjowLCJzaW5nbGVTdWJQYWdlSWQiOjAsImNoYW5uZWwiOjAsImNvdW50ZG93blJlcG9ydCI6ZmFsc2UsInRoZW1lVHlwZSI6MCwibWl4ZWRBZCI6dHJ1ZSwiZnVsbE1peGVkIjp0cnVlLCJhdXRvUmVwb3J0Ijp0cnVlLCJmcm9tVGFza0NlbnRlciI6dHJ1ZSwic2VhcmNoSW5zcGlyZVNjaGVtZUluZm8iOm51bGwsImFtb3VudCI6MH0="
},
follow: {
name: "关注广告",
pageId: 11101, subPageId: 100026367, businessId: 672, posId: 24067,
requestSceneType: 2, taskType: 1
},
content: {
name: "内容广告",
pageId: 11101, subPageId: 100141480, businessId: 7054, posId: 186550,
requestSceneType: 1, taskType: 1
}
}
}
};
let localPublicIP = null;
// ==============================================
// 工具函数(原代码未改动)
// ==============================================
function getTime() {
return new Date().toLocaleTimeString("zh-CN", {
timeZone: "Asia/Shanghai", hour12: false,
hour: "2-digit", minute: "2-digit", second: "2-digit"
});
}
function getProxyTag(useProxy) { return useProxy ? "[代理]" : "[直连]"; }
function maskProxyUrl(proxy) {
if (!proxy) return null;
try {
const match = proxy.match(/^(socks5:\/\/)([^:@]+)(?::([^@]+))?@(.+)$/);
if (match) {
const [, protocol, user, , host] = match;
return `${protocol}${user}:***@${host}`;
}
} catch (e) {}
return proxy;
}
function log(useProxy, appName, msg) {
const tag = getProxyTag(useProxy);
const app = appName === "快手极速版" ? "快手极速版" : "快手";
console.log(`${tag}<${app}>(${getTime()}): ${msg}`);
}
function print(msg) { console.log(msg); }
// ==============================================
// 网络请求封装(原代码未改动)
// ==============================================
async function request(options, proxy = null, title = "请求") {
try {
const axiosOptions = {
method: options.method || "GET",
url: options.url,
headers: options.headers || {},
data: options.body || options.form,
timeout: options.timeout || 12000,
validateStatus: () => true
};
if (proxy) {
const agent = new SocksProxyAgent(proxy, { timeout: 10000, keepAlive: false });
axiosOptions.httpAgent = agent;
axiosOptions.httpsAgent = agent;
} else {
axiosOptions.proxy = false;
}
if (options.form && options.method === "POST" && !axiosOptions.headers["Content-Type"]) {
axiosOptions.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8";
axiosOptions.data = querystring.stringify(options.form);
}
const resp = await axios(axiosOptions);
return { body: resp.data, status: resp.status };
} catch (e) {
console.log(`[请求失败] ${title}: ${e.message}`);
return { body: null, status: 0 };
}
}
async function checkLocalIP() {
print("正在检测本地直连公网IP...");
const urls = ["http://icanhazip.com", "http://ipinfo.io/ip", "http://httpbin.org/ip"];
for (const url of urls) {
try {
const res = await axios.get(url, { timeout: 5000, responseType: "text", proxy: false });
const ip = res.data.trim().match(/\d+\.\d+\.\d+\.\d+/)?.[0];
if (ip) {
localPublicIP = ip;
print("本地直连公网IP: " + ip);
return ip;
}
} catch (e) { continue; }
}
print("本地直连公网IP检测失败");
process.exit(1);
}
async function checkProxyIP(proxy) {
const urls = ["http://icanhazip.com", "http://ipinfo.io/ip", "http://httpbin.org/ip"];
for (const url of urls) {
try {
const { body } = await request({ method: "GET", url, timeout: 8000 }, proxy, "代理IP检测");
if (!body) continue;
const ip = body.toString().trim().match(/\d+\.\d+\.\d+\.\d+/)?.[0];
if (ip) return ip;
} catch (e) { continue; }
}
return null;
}
// ==============================================
// 签名接口 - 核心修改按kpn自动切换接口
// ==============================================
async function getEncSign(base64Data, proxy, appName, remark, kpnType) {
// 按kpn选签名接口KUAISHOU=81 NEBULA=82
const SIGN_API_URL = kpnType === "KUAISHOU" ? SIGN_API_KUAISHOU : SIGN_API_NEBULA;
try {
const { body } = await request({
method: "POST",
url: SIGN_API_URL + "/encsign",
headers: { "Content-Type": "application/json", "User-Agent": "Mozilla/5.0" },
body: JSON.stringify({ data: base64Data }),
timeout: 15000
}, null, `获取加密签名`);
if (body && body.status) return body.data;
log(proxy, appName, `${remark} encsign 失败: ${body?.message || body?.error || "无响应"}`);
return null;
} catch (e) {
log(proxy, appName, `${remark} encsign 异常: ${e.message}`);
return null;
}
}
async function getNsSign(reqInfo, proxy, appName, remark, kpnType) {
// 按kpn选签名接口KUAISHOU=81 NEBULA=82
const SIGN_API_URL = kpnType === "KUAISHOU" ? SIGN_API_KUAISHOU : SIGN_API_NEBULA;
try {
const payload = {
path: reqInfo.urlpath,
data: reqInfo.reqdata,
salt: reqInfo.salt
};
const { body } = await request({
method: "POST",
url: SIGN_API_URL + "/nssig",
headers: { "Content-Type": "application/json", "User-Agent": "Mozilla/5.0" },
body: JSON.stringify(payload),
timeout: 15000
}, null, `获取nssig签名`);
if (body && body.data) {
return {
sig: body.data.sig,
__NStokensig: body.data.nstokensig,
__NS_sig3: body.data.nssig3,
__NS_xfalcon: body.data.nssig4 || body.data.xfalcon || ""
};
}
log(proxy, appName, `${remark} nssig 失败: ${body?.error || body?.message || "无响应"}`);
return null;
} catch (e) {
log(proxy, appName, `${remark} nssig 异常: ${e.message}`);
return null;
}
}
// ==============================================
// 账号信息获取(原代码未改动)
// ==============================================
async function getUserInfo(cookie, platform, proxy) {
try {
const { body } = await request({
method: "GET",
url: platform.accountInfoUrl,
headers: {
Host: platform.host,
"User-Agent": "kwai-android aegon/3.56.0",
Cookie: cookie,
"Content-Type": "application/x-www-form-urlencoded"
},
timeout: 12000
}, proxy, "获取账号信息");
if (body && body.result === 1 && body.data) {
let coin = 0, cash = 0;
if (platform.name === "KS") {
coin = Number(body.data.coinAmount) || 0;
cash = Number(body.data.cashAmountDisplay) || 0;
} else {
coin = Number(body.data.totalCoin) || 0;
cash = Number(body.data.allCash) || 0;
}
return {
nickname: body.data.userData?.nickname || null,
totalCoin: coin, allCash: cash,
success: true, ckExpired: false
};
}
return { nickname: null, totalCoin: 0, allCash: 0, success: false, ckExpired: true };
} catch (e) {
return { nickname: null, totalCoin: 0, allCash: 0, success: false, ckExpired: true };
}
}
// ==============================================
// 账号任务类 - 仅传kpnType到签名函数其余未改
// ==============================================
class KuaishouAccount {
constructor({ index = 1, salt, cookie, remark = "未命名", proxyUrl = null, tasksToExecute = CONFIG.DEFAULT_TASKS }) {
this.index = index;
this.salt = salt;
this.cookie = cookie;
this.remark = remark;
this.proxyUrl = proxyUrl;
this.platform = this.getPlatformByCookie(cookie);
this.kpnType = this.platform.kpn; // 新增获取kpn类型(KUAISHOU/NEBULA)
this.tasksToRun = tasksToExecute.filter(Boolean);
this.taskConfigs = CONFIG.TASK_CONFIGS[this.platform.kpn === "NEBULA" ? "NEBULA" : "KUAISHOU"];
this.lowRewardCount = 0;
this.lowRewardStreak = 0;
this.adFailCount = 0;
this.continuous1Coin = 0;
this.stopAll = false;
this.taskStats = {};
this.taskLimit = {};
this.taskDisabled = {};
this.tasksToRun.forEach(task => {
this.taskStats[task] = { success: 0, failed: 0, totalReward: 0 };
this.taskLimit[task] = false;
this.taskDisabled[task] = false;
});
this.isCycleMode = CONFIG.CYCLE_ROUNDS > 0;
this.cycleRounds = CONFIG.CYCLE_ROUNDS;
this.currentRound = 0;
this.currentTaskIndex = 0;
this.parseCookie();
this.clientIP = null;
}
getPlatformByCookie(cookie) {
const match = cookie.match(/kpn=([^;]+)/);
const kpn = match ? match[1].toUpperCase() : "KUAISHOU";
return kpn === "NEBULA" ? CONFIG.PLATFORM_CONFIG.NEBULA : CONFIG.PLATFORM_CONFIG.KUAISHOU;
}
parseCookie() {
try {
this.mod = this.cookie.match(/mod=([^;]+)/)?.[1] || "Xiaomi(23116PN5BC)";
this.egid = this.cookie.match(/egid=([^;]+)/)?.[1] || "";
this.did = this.cookie.match(/did=([^;]+)/)?.[1] || "";
this.userId = this.cookie.match(/userId=([^;]+)/)?.[1] || "";
this.apiSt = this.cookie.match(/kuaishou\.api_st=([^;]+)/)?.[1] || "";
this.appver = this.cookie.match(/appver=([^;]+)/)?.[1] || "13.7.20.10468";
this.queryParams = `mod=${this.mod}&appver=${this.appver}&egid=${this.egid}&did=${this.did}`;
} catch (e) {
log(this.proxyUrl, this.platform.displayName, `${this.remark} 解析cookie失败: ${e.message}`);
}
}
async initIP() {
try {
if (this.proxyUrl) {
log(null, this.platform.displayName, `账号 [${this.remark}] 代理: ${maskProxyUrl(this.proxyUrl)}`);
const ip = await checkProxyIP(this.proxyUrl);
if (!ip) {
this.stopAll = true;
log(this.proxyUrl, this.platform.displayName, `${this.remark} 初始化失败代理IP检测无有效结果`);
return;
}
this.clientIP = ip;
log(this.proxyUrl, this.platform.displayName, `${this.remark} 代理出口IP: ${ip}`);
} else {
if (!localPublicIP) await checkLocalIP();
this.clientIP = localPublicIP;
}
} catch (e) {
this.stopAll = true;
log(this.proxyUrl, this.platform.displayName, `${this.remark} 初始化失败:${e.message}`);
}
}
async retry(fn, desc, times = 3, delay = 2000) {
let cnt = 0;
while (cnt < times && !this.stopAll) {
try {
const res = await fn();
if (res) return res;
} catch (e) {}
cnt++;
if (cnt < times && !this.stopAll) await new Promise(r => setTimeout(r, delay));
}
return null;
}
getImpExt(task) {
if (task.name.includes("搜索")) {
const word = CONFIG.SEARCH_KEYWORDS[Math.floor(Math.random() * CONFIG.SEARCH_KEYWORDS.length)];
return JSON.stringify({
openH5AdCount: 2,
sessionLookedCompletedCount: "1",
sessionType: "1",
searchKey: word,
triggerType: "2",
disableReportToast: "true",
businessEnterAction: "7",
neoParams: task.linkUrl || ""
});
}
return "{}";
}
async getAdInfo(taskKey) {
const task = this.taskConfigs[taskKey];
if (!task) return null;
const adUrl = "/rest/e/reward/mixed/ad";
const commonData = {
encData: "|encData|",
sign: "|sign|",
cs: "false",
client_key: this.platform.adClientKey,
videoModelCrowdTag: "1_23",
os: "android",
"kuaishou.api_st": this.apiSt,
uQaTag: "1##swLdgl:99#ecPp:-9#cmNt:-0#cmHs:-3#cmMnsl:-0"
};
const deviceData = {
earphoneMode: "1", mod: this.mod, appver: this.appver,
isp: "CUCC", language: "zh-cn", ud: this.userId,
did_tag: "0", net: "WIFI", kcv: "1599", app: "0",
kpf: "ANDROID_PHONE", ver: "11.6", android_os: "0",
boardPlatform: "pineapple", kpn: this.platform.kpn,
androidApiLevel: "35", country_code: "cn", sys: "ANDROID_15",
sw: "1080", sh: "2400", abi: "arm64", userRecoBit: "0"
};
const impData = {
appInfo: {
appId: this.platform.appId, name: this.platform.appName,
packageName: this.platform.packageName, version: this.appver, versionCode: -1
},
deviceInfo: { osType: 1, osVersion: "15", deviceId: this.did, screenSize: { width: 1080, height: 2249 }, ftt: "" },
userInfo: { userId: this.userId, age: 0, gender: "" },
impInfo: [{
pageId: task.pageId || 100011251,
subPageId: task.subPageId,
action: 0,
browseType: task.name.includes("搜索") ? 4 : 3,
impExtData: this.getImpExt(task),
mediaExtData: "{}"
}]
};
const base64Imp = Buffer.from(JSON.stringify(impData)).toString("base64");
// 传kpnType到签名函数
const encSign = await this.retry(
() => getEncSign(base64Imp, this.proxyUrl, this.platform.displayName, this.remark, this.kpnType),
"获取广告加密签名"
);
if (!encSign) return null;
commonData.encData = encSign.encdata;
commonData.sign = encSign.sign;
// 传kpnType到签名函数
const nsSign = await this.retry(
() => getNsSign({
urlpath: adUrl,
reqdata: querystring.stringify(commonData) + "&" + querystring.stringify(deviceData),
salt: this.salt
}, this.proxyUrl, this.platform.displayName, this.remark, this.kpnType),
"获取广告请求nssig"
);
if (!nsSign) return null;
const reqQuery = {
...deviceData,
sig: nsSign.sig,
__NS_sig3: nsSign.__NS_sig3,
__NS_xfalcon: nsSign.__NS_xfalcon,
__NStokensig: nsSign.__NStokensig
};
const finalUrl = "https://api.e.kuaishou.com" + adUrl + "?" + querystring.stringify(reqQuery);
const { body } = await request({
method: "POST",
url: finalUrl,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
Host: "api.e.kuaishou.com",
"User-Agent": "kwai-android aegon/3.56.0",
Cookie: this.cookie
},
form: commonData,
timeout: 12000
}, this.proxyUrl, "获取广告");
if (!body) {
this.adFailCount++;
if (this.adFailCount >= CONFIG.AD_FAIL_LIMIT) this.stopAll = true;
return null;
}
if (body.errorMsg === "OK" && body.feeds?.[0]?.ad) {
const ad = body.feeds[0];
const title = (ad.caption || ad.ad?.caption || "").slice(0, 30) + "...";
let coin = 0;
try {
const ext = JSON.parse(ad.ad.extData);
coin = Number(ext.awardCoin) || 0;
if (coin === 0) {
coin = ad.ad.adDataV2?.inspirePersonalize?.awardValue ||
ad.ad.adDataV2?.inspireAdInfo?.inspirePersonalize?.neoValue || 0;
}
} catch (e) {}
if (coin === 5) return null;
log(this.proxyUrl, this.platform.displayName, `${this.remark} 获取广告成功:${title}`);
log(null, this.platform.displayName, `${this.remark} 预计获得: ${coin} 金币`);
return {
cid: ad.ad.creativeId,
llsid: ad.exp_tag?.split("/")?.[1]?.split("_")?.[0] || "",
hasRewardEnd: ad.ad.adDataV2?.onceAgainRewardInfo?.hasMore || false,
expectedCoins: coin,
taskConfig: task
};
}
this.adFailCount++;
if (this.adFailCount >= CONFIG.AD_FAIL_LIMIT) this.stopAll = true;
return null;
}
async genReportSign(cid, llsid, task) {
try {
const bizStr = JSON.stringify({
businessId: task.businessId,
endTime: Date.now(),
extParams: "",
mediaScene: "video",
neoInfos: [{
creativeId: cid, extInfo: "", llsid,
requestSceneType: task.requestSceneType,
taskType: task.taskType,
watchExpId: "", watchStage: 0
}],
pageId: task.pageId || 100011251,
posId: task.posId,
reportType: 0,
sessionId: "",
startTime: Date.now() - 30000,
subPageId: task.subPageId
});
const postData = `bizStr=${encodeURIComponent(bizStr)}&cs=false&client_key=${this.platform.reportClientKey}`;
const qs = this.queryParams + "&" + postData;
// 传kpnType到签名函数
const sign = await this.retry(
() => getNsSign({
urlpath: "/rest/r/ad/task/report",
reqdata: qs,
salt: this.salt
}, this.proxyUrl, this.platform.displayName, this.remark, this.kpnType),
"生成报告签名"
);
if (!sign) return null;
return {
sig: sign.sig, sig3: sign.__NS_sig3,
xfalcon: sign.__NS_xfalcon, sigtoken: sign.__NStokensig,
post: postData
};
} catch (e) {
return null;
}
}
async submitReport(cid, llsid, taskKey, task) {
const sign = await this.genReportSign(cid, llsid, task);
if (!sign) return { success: false, reward: 0 };
const url = "https://api.e.kuaishou.com/rest/r/ad/task/report?" +
`${this.queryParams}&sig=${sign.sig}&__NS_sig3=${sign.sig3}&__NS_xfalcon=${sign.xfalcon}&__NStokensig=${sign.sigtoken}`;
const { body } = await request({
method: "POST",
url,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
Host: "api.e.kuaishou.com",
Cookie: this.cookie,
"User-Agent": "kwai-android aegon/3.56.0"
},
form: querystring.parse(sign.post),
timeout: 12000
}, this.proxyUrl, "提交任务报告");
if (!body) return { success: false, reward: 0 };
if (body.result === 1) {
const coin = Number(body.data?.neoAmount) || 0;
this.taskStats[taskKey].totalReward += coin;
if (coin === 1) {
this.continuous1Coin++;
if (this.continuous1Coin >= CONFIG.CONTINUOUS_1COIN_LIMIT) {
log(this.proxyUrl, this.platform.displayName, `${this.remark} 连续${CONFIG.CONTINUOUS_1COIN_LIMIT}次1金币停止任务`);
this.stopAll = true;
}
} else {
this.continuous1Coin = 0;
}
if (coin <= CONFIG.LOW_REWARD_THRESHOLD) {
this.lowRewardStreak++;
if (this.lowRewardStreak >= CONFIG.LOW_REWARD_LIMIT) {
log(this.proxyUrl, this.platform.displayName, `${this.remark} 连续低奖励超限,停止任务`);
this.stopAll = true;
}
} else {
this.lowRewardStreak = 0;
}
return { success: true, reward: coin };
}
if ([20107, 20108, 1003, 415].includes(body.result)) {
return { success: false, reward: 0, limitReached: true };
}
return { success: false, reward: 0 };
}
async runTask(taskKey) {
if (this.taskDisabled[taskKey] || this.taskLimit[taskKey] || this.stopAll) return { success: false, reward: 0 };
let adInfo = null;
while (!adInfo && !this.stopAll) {
adInfo = await this.getAdInfo(taskKey);
if (!adInfo && !this.stopAll) await new Promise(r => setTimeout(r, 3000));
}
if (!adInfo) {
this.taskStats[taskKey].failed++;
return { success: false, reward: 0 };
}
const watchMs = Math.floor(Math.random() * (CONFIG.WATCH_MAX - CONFIG.WATCH_MIN) + CONFIG.WATCH_MIN) * 1000;
log(this.proxyUrl, this.platform.displayName, `${this.remark} 观看广告中,等待 ${Math.round(watchMs/1000)} 秒...`);
await new Promise(r => setTimeout(r, watchMs));
log(this.proxyUrl, this.platform.displayName, `${this.remark} 观看完成,提交任务报告`);
const result = await this.submitReport(adInfo.cid, adInfo.llsid, taskKey, adInfo.taskConfig);
if (result.success) {
this.taskStats[taskKey].success++;
log(this.proxyUrl, this.platform.displayName, `${this.remark} ✅ 提交成功!获得 ${result.reward} 金币`);
return { success: true, reward: result.reward, hasRewardEnd: adInfo.hasRewardEnd };
}
if (result.limitReached) this.taskLimit[taskKey] = true;
this.taskStats[taskKey].failed++;
return { success: false, reward: 0, limitReached: result.limitReached || false };
}
nextTask() {
const available = this.tasksToRun.filter(t => !this.taskLimit[t] && !this.taskDisabled[t]);
if (available.length === 0 || this.stopAll) return null;
this.currentTaskIndex = (this.currentTaskIndex + 1) % available.length;
return available[this.currentTaskIndex];
}
async restAfterAd(count) {
if (count > 0 && count % CONFIG.APPEND_REST_INTERVAL === 0) {
const ms = Math.floor(Math.random() * (CONFIG.APPEND_REST_MAX - CONFIG.APPEND_REST_MIN)) + CONFIG.APPEND_REST_MIN;
await new Promise(r => setTimeout(r, ms));
}
}
async run() {
await this.initIP();
if (this.stopAll) {
return { success: false, remark: this.remark, platform: this.platform.name, taskCount: 0, totalReward: 0, exitIP: this.clientIP, stopReason: "初始化失败" };
}
const user = await getUserInfo(this.cookie, this.platform, this.proxyUrl);
if (!user.success || user.ckExpired) {
log(this.proxyUrl, this.platform.displayName, `${this.remark} Cookie已过期或无效`);
return { success: false, remark: this.remark, platform: this.platform.name, taskCount: 0, totalReward: 0, exitIP: this.clientIP, stopReason: "Cookie过期" };
}
log(this.proxyUrl, this.platform.displayName,
`${this.remark} 登录成功 | 昵称: ${user.nickname || "未知"} | 金币: ${user.totalCoin} | 余额: ${user.allCash.toFixed(2)}`);
let totalTasks = 0, appendTasks = 0, stopReason = "正常结束";
while (!this.stopAll) {
if (this.isCycleMode && this.currentRound >= this.cycleRounds) {
stopReason = `已完成${this.cycleRounds}轮任务`;
break;
}
const task = this.nextTask();
if (!task) { stopReason = "无可用任务"; this.stopAll = true; break; }
const res = await this.runTask(task);
totalTasks++;
if (res.hasRewardEnd) {
appendTasks++;
await this.restAfterAd(appendTasks);
await this.runTask(task);
}
if (this.adFailCount >= CONFIG.AD_FAIL_LIMIT) { stopReason = "广告获取失败达上限"; this.stopAll = true; }
if (this.nextTask() && !this.stopAll) {
const delay = Math.floor(Math.random() * 5 + 5) * 1000;
await new Promise(r => setTimeout(r, delay));
}
if (this.isCycleMode && this.currentTaskIndex === this.tasksToRun.length - 1) this.currentRound++;
}
const totalReward = Object.values(this.taskStats).reduce((s, t) => s + t.totalReward, 0);
log(this.proxyUrl, this.platform.displayName,
`${this.remark} 结束 | 执行任务: ${totalTasks} | 总获金币: ${totalReward} | 原因: ${stopReason}`);
for (const [k, s] of Object.entries(this.taskStats)) {
const cfg = this.taskConfigs[k];
if (cfg) log(null, this.platform.displayName, `${cfg.name}: 成功${s.success}次 失败${s.failed}次 奖励${s.totalReward}金币`);
}
return { success: true, remark: this.remark, platform: this.platform.name, taskCount: totalTasks, appendCount: appendTasks, totalReward, exitIP: this.clientIP, stopReason };
}
}
// ==============================================
// 账号解析 & 批量执行(原代码未改动)
// ==============================================
function parseAccountLine(line, index) {
if (!line || typeof line !== "string") return null;
const parts = line.split("#");
if (parts.length < 3) return null;
const remark = parts[0].trim() || `账号${index}`;
const cookie = parts[1].trim();
const salt = parts[2].trim();
let proxy = parts[3]?.trim() || null;
if (!cookie || !salt) return null;
if (proxy && proxy.includes("|")) {
const [host, port, user, pwd] = proxy.split("|");
proxy = `socks5://${user}:${pwd}@${host}:${port}`;
}
if (proxy && !/^socks5:\/\//i.test(proxy)) {
console.log(`⚠️ 账号${index} 代理格式非socks5已忽略: ${proxy}`);
proxy = null;
}
return { cookie, salt, remark, proxyUrl: proxy };
}
function loadAllAccounts() {
const accounts = [];
const exists = new Set();
let index = 1;
let proxyCount = 0;
const mainCk = process.env.ksck;
if (mainCk) {
mainCk.split("&").forEach(line => {
line = line.trim();
if (line && !exists.has(line)) {
const acc = parseAccountLine(line, index++);
if (acc) { accounts.push(acc); exists.add(line); if (acc.proxyUrl) proxyCount++; }
}
});
}
for (let i = 1; i <= 666; i++) {
const line = process.env[`ksck${i}`]?.trim();
if (line && !exists.has(line)) {
const acc = parseAccountLine(line, index++);
if (acc) { accounts.push(acc); exists.add(line); if (acc.proxyUrl) proxyCount++; }
}
}
print(`\n✅ 共加载账号: ${accounts.length} 个(其中代理账号: ${proxyCount} 个)`);
return accounts;
}
async function runAccountList(accounts) {
const results = [];
for (let i = 0; i < accounts.length; i++) {
const acc = accounts[i];
print(`\n${"=".repeat(60)}`);
print(`🚀 开始执行账号 ${i+1}/${accounts.length}: ${acc.remark}`);
print(`${"=".repeat(60)}`);
const instance = new KuaishouAccount({ ...acc, index: i + 1 });
const result = await instance.run();
results.push(result);
}
return results;
}
function printSummary(results) {
print(`\n${"=".repeat(60)}`);
print(" 📊 全部账号执行结果汇总");
print(`${"=".repeat(60)}`);
let totalReward = 0;
results.forEach((r, i) => {
const tag = r.platform === "JSB" ? "[极速版]" : "[快手 ]";
print(`${tag} 账号${i+1} ${r.remark} | 任务数:${r.taskCount} | 金币:${r.totalReward} | ${r.stopReason}`);
totalReward += r.totalReward || 0;
});
print(`${"=".repeat(60)}`);
print(` 🎉 全部完成 | 账号数: ${results.length} | 总金币: ${totalReward}`);
print(`${"=".repeat(60)}`);
}
// ==============================================
// 启动(原代码未改动)
// ==============================================
print("================================================================================");
print(" ⭐ 快手双端脚本 ⭐ ");
print(" 支持快手 & 快手极速版 · 无需卡密授权 · 按kpn自动切换签名接口 ");
print("================================================================================");
print(`\n🎯 默认任务: ${CONFIG.DEFAULT_TASKS.join(", ")}`);
print(`⏱ 观看时长: ${CONFIG.WATCH_MIN}-${CONFIG.WATCH_MAX}`);
print(`🔄 循环轮数: ${CONFIG.CYCLE_ROUNDS > 0 ? CONFIG.CYCLE_ROUNDS : "无限制"}`);
print("\n📋 环境变量说明:");
print(" ksck = 账号配置,格式: 备注#cookie#salt#socks5代理(可选)");
print(" ksck1~ksck666 = 多账号扩展");
print(" KS_DEFAULT_TASKS = 任务列表,逗号分隔,可选: box,look,food,search");
print(" KS_CYCLE_ROUNDS = 循环轮数 (0=无限)");
print(" KS_WATCH_MIN/MAX = 广告观看秒数范围");
print(" KS_LOW_REWARD_THRESHOLD = 低奖励阈值");
print(" KS_LOW_REWARD_LIMIT = 连续低奖励停止次数");
print("================================================================================\n");
(async () => {
const accounts = loadAllAccounts();
if (accounts.length === 0) {
print("❌ 未检测到账号配置,请设置 ksck 环境变量");
print(" 格式: 备注#cookie字符串#salt值");
print(" 示例: 我的账号#did=xxx;userId=yyy;...#abcdef1234");
process.exit(1);
}
const results = await runAccountList(accounts);
printSummary(results);
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long