├── README.md ├── Script ├── RouterResetIP.js ├── Routerinfo.js ├── bot_jd_CkSeq.js ├── bot_jd_bean_change.js ├── bot_jd_bean_change_QL.js ├── bot_jd_bean_info.js └── bot_jd_bean_info_QL.js ├── config └── ccbotSetting.json └── jbot ├── bot ├── bean.py ├── beandata.py ├── chart.py ├── getfile.py ├── geturlfile.py └── utils.py ├── diy ├── CheckCK.py ├── Router.py ├── ccbean.py ├── cxjc.py └── download.py ├── user ├── bean_Global.py ├── beaninfo_Global.py ├── ccbean_Global.py ├── chart_Global.py ├── jinffen_Global.py ├── jupai.py ├── jxjd_Global.py ├── reply_msg.py └── weather_Global.py └── utils.py /README.md: -------------------------------------------------------------------------------- 1 | # QL_DIYBOT 2 | 写点有用且好玩的bot模块 3 | 4 | # 注意事项: 5 | 6 | 机器人模块的使用环境是青龙bot + diybot,V4 + diybot 7 | 配置文件统一是ql\config\ccbotSetting.json,文件库里有,说明在配置文件里. 8 | 9 | # 1.jbot\diy\cxjc.py 10 | 11 | 作用: 发送/cx 给机器人查询现在执行的任务列表,点击前面的链接即可强制结束进程. 12 | 安装: 文件放于ql\jbot\diy,重启机器人即可生效. 13 | 14 | # 2.jbot\diy\Router.py 15 | 16 | 作用: 梅林路由器专用,发送/routerinfo 给机器人查询路由器ip等信息 17 | 发送/routerip 给机器人通知路由器重新拨号换IP. 18 | 安装: 1.Routerinfo.js RouterResetIP.js填上路由器相关信息,并将文件放到青龙,修改配置文件的文件地址. 19 | 2.安装nodejs依赖ssh2 20 | 3.重启机器人即可生效 21 | 22 | # 3.jbot\diy\ccbean.py (以前的Bean_ccwav.py记得删除) 23 | 24 | (甘露殿狗哥测试了V4可以正常使用........) 25 | 作用: 调用资产查询脚本查询对应CK的资产信息. 支持/ccbean 和 /ccbean CK序号 两种格式. 26 | 安装: 文件放于ql\jbot\diy,修改配置文件的文件地址,重启机器人即可生效. 27 | 28 | # 5.jbot\user\ccbean_Global.py (全局版本) 29 | 30 | 全局版本,tg任何群使用cb CK序号或cb ptpin两种格式查询资产. 31 | 安装: 文件放于ql\jbot\user,修改配置文件的文件地址,重启机器人即可生效. 32 | 33 | # 6.jbot\user\bean_Global.py (全局版本) 34 | 35 | Bean.py的全局版本,bb CK序号查询资产. 36 | 安装: 文件放于ql\jbot\user,重启机器人即可生效. 37 | 38 | # 7.jbot\user\chart_Global.py (全局版本) 39 | 40 | chart.py的全局版本,bc CK序号查询资产. 41 | 安装: 文件放于ql\jbot\user,重启机器人即可生效. 42 | 43 | # 8.jbot\bot\bean.py 44 | 45 | 作用: 增强原有的/bean,不带序号时弹出按钮 46 | 安装: 文件放于ql\jbot\bot(同时放在ql\repo\dockerbot\jbot\bot),重启机器人即可生效. 47 | 48 | # 9.jbot\bot\chart.py 49 | 50 | 作用: 增强原有的/chart,不带序号时弹出按钮 51 | 安装: 文件放于ql\jbot\bot(同时放在ql\repo\dockerbot\jbot\bot),重启机器人即可生效. 52 | 53 | # 10.jbot\diy\CheckCK.py (青龙专用) 54 | 55 | 作用: 导出现有的CK信息,命令是/cck 56 | 安装: 1.CheckCK.py第20行的文件路径 57 | 2.将修改后的CheckCK.py文件放于ql\jbot\diy(同时放在ql\repo\dockerbot\jbot\diy) 58 | 3.重启机器人即可生效 59 | 60 | # 11.jbot\user\beaninfo_Global.py (全局版本) 61 | bd CK序号查询当日资产详情, 62 | 安装: 文件放于ql\jbot\user,修改配置文件的文件地址,重启机器人即可生效. 63 | 64 | # 12.一些原版的bug修复: 65 | jbot\utils.py: 修复user文件夹脚本载入时login.py没有优先载入导致部分全局命令不生效的问题. 66 | 安装: 文件放于ql\jbot\(同时放在ql\repo\dockerbot\jbot\),重启机器人即可生效. 67 | 68 | # 13.jbot\user\jxjd_Global.py (全局版本) 69 | 解析京东 京喜 京东极速版口令为网址,用法是jx 口令 或者 选中他人口令回复jx 70 | 安装: 文件放于ql\jbot\user(同时放在ql\repo\dockerbot\jbot\user),重启机器人即可生效. 71 | 72 | # 14.jbot\user\weather_Global.py (全局版本) 73 | 查询天气,例如 深圳天气 74 | 安装: 文件放于ql\jbot\user,修改配置文件的文件地址,重启机器人即可生效. 75 | 76 | # 15.jbot\bot\getfile.py 77 | 安装: 文件放于ql\jbot\bot(同时放在ql\repo\dockerbot\jbot\bot),修改配置文件的文件地址,重启机器人即可生效. 78 | 79 | # 16.jbot\user\jupai.py 80 | 发送举牌小人图片,格式: jp 内容,或者对内容回复jp. 81 | 安装: 文件放于ql\jbot\user,重启机器人即可生效. 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /Script/RouterResetIP.js: -------------------------------------------------------------------------------- 1 | var Client = require('ssh2').Client; 2 | var conn = new Client(); 3 | var strreturn="" 4 | //路由器ip 5 | var RouterIP='192.168.1.1' 6 | //ssh端口 7 | var RouterSSHProt=22 8 | //ssh用户名密码 9 | var RouterSSHUser="ccwav" 10 | var RouterSSHPsw="AABBCCDD" 11 | //路由器重拨号命令 12 | let strcommond="service restart_wan" 13 | 14 | !(async() => { 15 | await conn.on('ready', function () { 16 | conn.exec(strcommond, function (err, stream) { 17 | if (err) 18 | throw err; 19 | stream.on('close', function (code, signal) { 20 | conn.end(); 21 | }).on('data', function (data) { 22 | console.log("重拨结果:"+":"+data.toString().replace("\n","").replace("Done","成功")); 23 | }).stderr.on('data', function (data) { 24 | console.log('STDERR: ' + data); 25 | }); 26 | }); 27 | }).connect({ 28 | host: RouterIP, 29 | port: RouterSSHProt, 30 | username: RouterSSHUser, 31 | password: RouterSSHPsw 32 | }); 33 | 34 | 35 | })() -------------------------------------------------------------------------------- /Script/Routerinfo.js: -------------------------------------------------------------------------------- 1 | var Client = require('ssh2').Client; 2 | var conn = new Client(); 3 | var strreturn="" 4 | //路由器ip 5 | var RouterIP='192.168.1.1' 6 | //ssh端口 7 | var RouterSSHProt=22 8 | //ssh用户名密码 9 | var RouterSSHUser="ccwav" 10 | var RouterSSHPsw="AABBCCDD" 11 | 12 | !(async() => { 13 | await conn.on('ready', function () { 14 | var intseq=0; 15 | var strTemp="设备名称|外网地址|内网地址|内存信息"; 16 | var sstrTitle=strTemp.split('|'); 17 | conn.exec("nvram get computer_name&&curl ip.sb&&nvram get lan_ipaddr&&top -n 1 -b |grep ^Mem", function (err, stream) { 18 | if (err) 19 | throw err; 20 | stream.on('close', function (code, signal) { 21 | conn.end(); 22 | }).on('data', function (data) { 23 | console.log(sstrTitle[intseq]+":"+data.toString().replace("\n","").replace("Mem: ","")); 24 | intseq++; 25 | }).stderr.on('data', function (data) { 26 | console.log('STDERR: ' + data); 27 | }); 28 | }); 29 | }).connect({ 30 | host: RouterIP, 31 | port: RouterSSHProt, 32 | username: RouterSSHUser, 33 | password: RouterSSHPsw 34 | }); 35 | 36 | 37 | })() -------------------------------------------------------------------------------- /Script/bot_jd_CkSeq.js: -------------------------------------------------------------------------------- 1 | /* 2 | cron "0 0 * * *" jd_CheckCkSeq.js, tag:CK顺序调试工具by-ccwav 3 | */ 4 | const $ = new Env("机器人专用CK状态工具"); 5 | const { 6 | getEnvs 7 | } = require('./ql'); 8 | const jdCookieNode = $.isNode() ? require("./jdCookie.js") : ""; 9 | let cookiesArr = []; 10 | if ($.isNode()) { 11 | Object.keys(jdCookieNode).forEach((item) => { 12 | cookiesArr.push(jdCookieNode[item]) 13 | }) 14 | } 15 | 16 | let arrCkPtPin = []; 17 | let arrEnvPtPin = []; 18 | let arrEnvStatus = []; 19 | let arrEnvOnebyOne = []; 20 | let arrEnvRemark = []; 21 | let strCk = ""; 22 | let strNoFoundCk = ""; 23 | 24 | const fs = require('fs'); 25 | let TempCKUid = []; 26 | let strUidFile = '/ql/scripts/CK_WxPusherUid.json'; 27 | let UidFileexists = fs.existsSync(strUidFile); 28 | if (UidFileexists) { 29 | console.log("检测到一对一Uid文件WxPusherUid.json,载入..."); 30 | TempCKUid = fs.readFileSync(strUidFile, 'utf-8'); 31 | if (TempCKUid) { 32 | TempCKUid = TempCKUid.toString(); 33 | TempCKUid = JSON.parse(TempCKUid); 34 | } 35 | } 36 | 37 | !(async() => { 38 | 39 | const envs = await getEnvs(); 40 | for (let i = 0; i < envs.length; i++) { 41 | if (envs[i].value) { 42 | var tempptpin = decodeURIComponent(envs[i].value.match(/pt_pin=([^; ]+)(?=;?)/) && envs[i].value.match(/pt_pin=([^; ]+)(?=;?)/)[1]); 43 | arrEnvPtPin.push(tempptpin); 44 | arrEnvStatus.push(envs[i].status); 45 | var struuid=getuuid(envs[i].remarks,tempptpin) 46 | arrEnvOnebyOne.push(struuid); 47 | var strRemark=getRemark(envs[i].remarks) 48 | arrEnvRemark.push(strRemark); 49 | } 50 | } 51 | 52 | for (let i = 0; i < cookiesArr.length; i++) { 53 | if (cookiesArr[i]) { 54 | cookie = cookiesArr[i]; 55 | var tempptpin = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]); 56 | var intSeq = inArray(tempptpin, arrEnvPtPin); 57 | if (intSeq != -1) { 58 | arrCkPtPin.push(tempptpin); 59 | if (arrEnvRemark[intSeq]) 60 | strCk += "【"+(intSeq+1) + "】" + arrEnvRemark[intSeq]; 61 | else 62 | strCk += "【"+(intSeq+1) + "】" + tempptpin ; 63 | 64 | if (arrEnvOnebyOne[intSeq]) { 65 | strCk += "(一对一)" 66 | } 67 | strCk +="\n"; 68 | } 69 | } 70 | } 71 | 72 | for (let i = 0; i < arrEnvPtPin.length; i++) { 73 | var tempptpin = arrEnvPtPin[i]; 74 | var intSeq = inArray(tempptpin, arrCkPtPin); 75 | if (intSeq == -1) { 76 | if (arrEnvRemark[i]) 77 | strNoFoundCk += "【" + (i + 1) + "】" + arrEnvRemark[i]; 78 | else 79 | strNoFoundCk += "【" + (i + 1) + "】" + tempptpin; 80 | 81 | if (arrEnvStatus[i] == 1) { 82 | strNoFoundCk += "(禁用状态)" 83 | } 84 | if (arrEnvOnebyOne[i]) { 85 | strNoFoundCk += "(一对一)" 86 | } 87 | strNoFoundCk += "\n"; 88 | 89 | } 90 | } 91 | console.log("😀今日正常的账号("+cookiesArr.length+"个):\n" + strCk); 92 | console.log("分割行"); 93 | if (strNoFoundCk) { 94 | console.log("\n😒没有出现在CK队列中的账号("+(arrEnvPtPin.length-cookiesArr.length)+"个):\n" + strNoFoundCk); 95 | } 96 | return; 97 | })() 98 | .catch((e) => $.logErr(e)) 99 | .finally(() => $.done()); 100 | 101 | function inArray(search, array) { 102 | var lnSeq = -1; 103 | for (let i = 0; i < array.length; i++) { 104 | if (array[i] == search) { 105 | lnSeq = i; 106 | } 107 | } 108 | return parseInt(lnSeq); 109 | } 110 | 111 | function getuuid(strRemark, PtPin) { 112 | var strTempuuid = ""; 113 | if (strRemark) { 114 | var Tempindex = strRemark.indexOf("@@"); 115 | if (Tempindex != -1) { 116 | //console.log(PtPin + ": 检测到NVJDC的一对一格式,瑞思拜~!"); 117 | var TempRemarkList = strRemark.split("@@"); 118 | for (let j = 1; j < TempRemarkList.length; j++) { 119 | if (TempRemarkList[j]) { 120 | if (TempRemarkList[j].length > 4) { 121 | if (TempRemarkList[j].substring(0, 4) == "UID_") { 122 | strTempuuid = TempRemarkList[j]; 123 | break; 124 | } 125 | } 126 | } 127 | } 128 | } 129 | } 130 | if (!strTempuuid && TempCKUid) { 131 | //console.log("正在从CK_WxPusherUid文件中检索资料..."); 132 | for (let j = 0; j < TempCKUid.length; j++) { 133 | if (PtPin == decodeURIComponent(TempCKUid[j].pt_pin)) { 134 | strTempuuid = TempCKUid[j].Uid; 135 | break; 136 | } 137 | } 138 | } 139 | return strTempuuid; 140 | } 141 | 142 | function getRemark(strRemark) { 143 | var strTempRemark = ""; 144 | if (strRemark) { 145 | var Tempindex = strRemark.indexOf("@@"); 146 | if (Tempindex != -1) { 147 | var TempRemarkList = strRemark.split("@@"); 148 | strTempRemark=TempRemarkList[0]; 149 | } else{ 150 | strTempRemark=strRemark; 151 | } 152 | } 153 | 154 | return strTempRemark; 155 | } 156 | 157 | // prettier-ignore 158 | function Env(t, e) { 159 | "undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0); 160 | class s { 161 | constructor(t) { 162 | this.env = t 163 | } 164 | send(t, e = "GET") { 165 | t = "string" == typeof t ? { 166 | url: t 167 | } 168 | : t; 169 | let s = this.get; 170 | return "POST" === e && (s = this.post), 171 | new Promise((e, i) => { 172 | s.call(this, t, (t, s, r) => { 173 | t ? i(t) : e(s) 174 | }) 175 | }) 176 | } 177 | get(t) { 178 | return this.send.call(this.env, t) 179 | } 180 | post(t) { 181 | return this.send.call(this.env, t, "POST") 182 | } 183 | } 184 | return new class { 185 | constructor(t, e) { 186 | this.name = t, 187 | this.http = new s(this), 188 | this.data = null, 189 | this.dataFile = "box.dat", 190 | this.logs = [], 191 | this.isMute = !1, 192 | this.isNeedRewrite = !1, 193 | this.logSeparator = "\n", 194 | this.startTime = (new Date).getTime(), 195 | Object.assign(this, e), 196 | this.log("", `🔔${this.name}, 开始!`) 197 | } 198 | isNode() { 199 | return "undefined" != typeof module && !!module.exports 200 | } 201 | isQuanX() { 202 | return "undefined" != typeof $task 203 | } 204 | isSurge() { 205 | return "undefined" != typeof $httpClient && "undefined" == typeof $loon 206 | } 207 | isLoon() { 208 | return "undefined" != typeof $loon 209 | } 210 | toObj(t, e = null) { 211 | try { 212 | return JSON.parse(t) 213 | } catch { 214 | return e 215 | } 216 | } 217 | toStr(t, e = null) { 218 | try { 219 | return JSON.stringify(t) 220 | } catch { 221 | return e 222 | } 223 | } 224 | getjson(t, e) { 225 | let s = e; 226 | const i = this.getdata(t); 227 | if (i) 228 | try { 229 | s = JSON.parse(this.getdata(t)) 230 | } catch {} 231 | return s 232 | } 233 | setjson(t, e) { 234 | try { 235 | return this.setdata(JSON.stringify(t), e) 236 | } catch { 237 | return !1 238 | } 239 | } 240 | getScript(t) { 241 | return new Promise(e => { 242 | this.get({ 243 | url: t 244 | }, (t, s, i) => e(i)) 245 | }) 246 | } 247 | runScript(t, e) { 248 | return new Promise(s => { 249 | let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); 250 | i = i ? i.replace(/\n/g, "").trim() : i; 251 | let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); 252 | r = r ? 1 * r : 20, 253 | r = e && e.timeout ? e.timeout : r; 254 | const[o, h] = i.split("@"), 255 | n = { 256 | url: `http://${h}/v1/scripting/evaluate`, 257 | body: { 258 | script_text: t, 259 | mock_type: "cron", 260 | timeout: r 261 | }, 262 | headers: { 263 | "X-Key": o, 264 | Accept: "*/*" 265 | } 266 | }; 267 | this.post(n, (t, e, i) => s(i)) 268 | }).catch(t => this.logErr(t)) 269 | } 270 | loaddata() { 271 | if (!this.isNode()) 272 | return {}; { 273 | this.fs = this.fs ? this.fs : require("fs"), 274 | this.path = this.path ? this.path : require("path"); 275 | const t = this.path.resolve(this.dataFile), 276 | e = this.path.resolve(process.cwd(), this.dataFile), 277 | s = this.fs.existsSync(t), 278 | i = !s && this.fs.existsSync(e); 279 | if (!s && !i) 280 | return {}; { 281 | const i = s ? t : e; 282 | try { 283 | return JSON.parse(this.fs.readFileSync(i)) 284 | } catch (t) { 285 | return {} 286 | } 287 | } 288 | } 289 | } 290 | writedata() { 291 | if (this.isNode()) { 292 | this.fs = this.fs ? this.fs : require("fs"), 293 | this.path = this.path ? this.path : require("path"); 294 | const t = this.path.resolve(this.dataFile), 295 | e = this.path.resolve(process.cwd(), this.dataFile), 296 | s = this.fs.existsSync(t), 297 | i = !s && this.fs.existsSync(e), 298 | r = JSON.stringify(this.data); 299 | s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) 300 | } 301 | } 302 | lodash_get(t, e, s) { 303 | const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); 304 | let r = t; 305 | for (const t of i) 306 | if (r = Object(r)[t], void 0 === r) 307 | return s; 308 | return r 309 | } 310 | lodash_set(t, e, s) { 311 | return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, i) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[i + 1]) >> 0 == +e[i + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) 312 | } 313 | getdata(t) { 314 | let e = this.getval(t); 315 | if (/^@/.test(t)) { 316 | const[, s, i] = /^@(.*?)\.(.*?)$/.exec(t), 317 | r = s ? this.getval(s) : ""; 318 | if (r) 319 | try { 320 | const t = JSON.parse(r); 321 | e = t ? this.lodash_get(t, i, "") : e 322 | } catch (t) { 323 | e = "" 324 | } 325 | } 326 | return e 327 | } 328 | setdata(t, e) { 329 | let s = !1; 330 | if (/^@/.test(e)) { 331 | const[, i, r] = /^@(.*?)\.(.*?)$/.exec(e), 332 | o = this.getval(i), 333 | h = i ? "null" === o ? null : o || "{}" : "{}"; 334 | try { 335 | const e = JSON.parse(h); 336 | this.lodash_set(e, r, t), 337 | s = this.setval(JSON.stringify(e), i) 338 | } catch (e) { 339 | const o = {}; 340 | this.lodash_set(o, r, t), 341 | s = this.setval(JSON.stringify(o), i) 342 | } 343 | } else 344 | s = this.setval(t, e); 345 | return s 346 | } 347 | getval(t) { 348 | return this.isSurge() || this.isLoon() ? $persistentStore.read(t) : this.isQuanX() ? $prefs.valueForKey(t) : this.isNode() ? (this.data = this.loaddata(), this.data[t]) : this.data && this.data[t] || null 349 | } 350 | setval(t, e) { 351 | return this.isSurge() || this.isLoon() ? $persistentStore.write(t, e) : this.isQuanX() ? $prefs.setValueForKey(t, e) : this.isNode() ? (this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0) : this.data && this.data[e] || null 352 | } 353 | initGotEnv(t) { 354 | this.got = this.got ? this.got : require("got"), 355 | this.cktough = this.cktough ? this.cktough : require("tough-cookie"), 356 | this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, 357 | t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) 358 | } 359 | get(t, e = (() => {})) { 360 | t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), 361 | this.isSurge() || this.isLoon() ? (this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { 362 | "X-Surge-Skip-Scripting": !1 363 | })), $httpClient.get(t, (t, s, i) => { 364 | !t && s && (s.body = i, s.statusCode = s.status), 365 | e(t, s, i) 366 | })) : this.isQuanX() ? (this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { 367 | hints: !1 368 | })), $task.fetch(t).then(t => { 369 | const { 370 | statusCode: s, 371 | statusCode: i, 372 | headers: r, 373 | body: o 374 | } = t; 375 | e(null, { 376 | status: s, 377 | statusCode: i, 378 | headers: r, 379 | body: o 380 | }, o) 381 | }, t => e(t))) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { 382 | try { 383 | if (t.headers["set-cookie"]) { 384 | const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); 385 | s && this.ckjar.setCookieSync(s, null), 386 | e.cookieJar = this.ckjar 387 | } 388 | } catch (t) { 389 | this.logErr(t) 390 | } 391 | }).then(t => { 392 | const { 393 | statusCode: s, 394 | statusCode: i, 395 | headers: r, 396 | body: o 397 | } = t; 398 | e(null, { 399 | status: s, 400 | statusCode: i, 401 | headers: r, 402 | body: o 403 | }, o) 404 | }, t => { 405 | const { 406 | message: s, 407 | response: i 408 | } = t; 409 | e(s, i, i && i.body) 410 | })) 411 | } 412 | post(t, e = (() => {})) { 413 | if (t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"), t.headers && delete t.headers["Content-Length"], this.isSurge() || this.isLoon()) 414 | this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { 415 | "X-Surge-Skip-Scripting": !1 416 | })), $httpClient.post(t, (t, s, i) => { 417 | !t && s && (s.body = i, s.statusCode = s.status), 418 | e(t, s, i) 419 | }); 420 | else if (this.isQuanX()) 421 | t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { 422 | hints: !1 423 | })), $task.fetch(t).then(t => { 424 | const { 425 | statusCode: s, 426 | statusCode: i, 427 | headers: r, 428 | body: o 429 | } = t; 430 | e(null, { 431 | status: s, 432 | statusCode: i, 433 | headers: r, 434 | body: o 435 | }, o) 436 | }, t => e(t)); 437 | else if (this.isNode()) { 438 | this.initGotEnv(t); 439 | const { 440 | url: s, 441 | ...i 442 | } = t; 443 | this.got.post(s, i).then(t => { 444 | const { 445 | statusCode: s, 446 | statusCode: i, 447 | headers: r, 448 | body: o 449 | } = t; 450 | e(null, { 451 | status: s, 452 | statusCode: i, 453 | headers: r, 454 | body: o 455 | }, o) 456 | }, t => { 457 | const { 458 | message: s, 459 | response: i 460 | } = t; 461 | e(s, i, i && i.body) 462 | }) 463 | } 464 | } 465 | time(t, e = null) { 466 | const s = e ? new Date(e) : new Date; 467 | let i = { 468 | "M+": s.getMonth() + 1, 469 | "d+": s.getDate(), 470 | "H+": s.getHours(), 471 | "m+": s.getMinutes(), 472 | "s+": s.getSeconds(), 473 | "q+": Math.floor((s.getMonth() + 3) / 3), 474 | S: s.getMilliseconds() 475 | }; 476 | /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); 477 | for (let e in i) 478 | new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? i[e] : ("00" + i[e]).substr(("" + i[e]).length))); 479 | return t 480 | } 481 | msg(e = t, s = "", i = "", r) { 482 | const o = t => { 483 | if (!t) 484 | return t; 485 | if ("string" == typeof t) 486 | return this.isLoon() ? t : this.isQuanX() ? { 487 | "open-url": t 488 | } 489 | : this.isSurge() ? { 490 | url: t 491 | } 492 | : void 0; 493 | if ("object" == typeof t) { 494 | if (this.isLoon()) { 495 | let e = t.openUrl || t.url || t["open-url"], 496 | s = t.mediaUrl || t["media-url"]; 497 | return { 498 | openUrl: e, 499 | mediaUrl: s 500 | } 501 | } 502 | if (this.isQuanX()) { 503 | let e = t["open-url"] || t.url || t.openUrl, 504 | s = t["media-url"] || t.mediaUrl; 505 | return { 506 | "open-url": e, 507 | "media-url": s 508 | } 509 | } 510 | if (this.isSurge()) { 511 | let e = t.url || t.openUrl || t["open-url"]; 512 | return { 513 | url: e 514 | } 515 | } 516 | } 517 | }; 518 | if (this.isMute || (this.isSurge() || this.isLoon() ? $notification.post(e, s, i, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) { 519 | let t = ["", "==============📣系统通知📣=============="]; 520 | t.push(e), 521 | s && t.push(s), 522 | i && t.push(i), 523 | console.log(t.join("\n")), 524 | this.logs = this.logs.concat(t) 525 | } 526 | } 527 | log(...t) { 528 | t.length > 0 && (this.logs = [...this.logs, ...t]), 529 | console.log(t.join(this.logSeparator)) 530 | } 531 | logErr(t, e) { 532 | const s = !this.isSurge() && !this.isQuanX() && !this.isLoon(); 533 | s ? this.log("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t) 534 | } 535 | wait(t) { 536 | return new Promise(e => setTimeout(e, t)) 537 | } 538 | done(t = {}) { 539 | const e = (new Date).getTime(), 540 | s = (e - this.startTime) / 1e3; 541 | this.log("", `🔔${this.name}, 结束! 🕛 ${s} 秒`), 542 | this.log(), 543 | (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t) 544 | } 545 | } 546 | (t, e) 547 | } 548 | -------------------------------------------------------------------------------- /Script/bot_jd_bean_info.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 详细版京东京豆统计 3 | 4 | * 默认不发送通知。 5 | 6 | [task_local] 7 | #京豆详情统计 8 | 20 22 * * * jd_bean_info.js, tag=京豆详情统计, img-url=https://raw.githubusercontent.com/Orz-3/mini/master/Color/jd.png, enabled=true 9 | * */ 10 | const $ = new Env('京豆详情统计'); 11 | const jdCookieNode = $.isNode() ? require('./jdCookie.js') : ''; 12 | let allMessage = ''; 13 | let myMap = new Map(); 14 | let allBean = 0; 15 | let JinQibean=""; 16 | //IOS等用户直接用NobyDa的jd cookie 17 | let cookiesArr = [], cookie = ''; 18 | if ($.isNode()) { 19 | Object.keys(jdCookieNode).forEach((item) => { 20 | cookiesArr.push(jdCookieNode[item]) 21 | }) 22 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => {}; 23 | } else { 24 | cookiesArr = [$.getdata('CookieJD'), $.getdata('CookieJD2'), ...jsonParse($.getdata('CookiesJD') || "[]").map(item => item.cookie)].filter(item => !!item); 25 | } 26 | 27 | let intcheckckseq=999999; 28 | let strcheckck = process.env.BOTCHECKCODE; 29 | let lnShowTop = 0; 30 | if(!strcheckck){ 31 | console.log("【账号�】没有获取到要查询的账号"); 32 | return 33 | } 34 | if ($.isNode() && process.env.BOTShowTopNum) { 35 | lnShowTop = parseInt(process.env.BOTShowTopNum); 36 | } 37 | let lnShowJinQiNum = 3; 38 | if ($.isNode() && process.env.BOTShowJinQiNum) { 39 | lnShowJinQiNum = parseInt(process.env.BOTShowJinQiNum); 40 | } 41 | 42 | for (i = 0; i < cookiesArr.length; i++) { 43 | if (cookiesArr[i]) { 44 | cookie = cookiesArr[i]; 45 | $.pt_pin = (cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]); 46 | if (strcheckck == $.pt_pin) { 47 | intcheckckseq = i; 48 | break; 49 | } 50 | } 51 | } 52 | 53 | if (intcheckckseq == 999999) { 54 | if (IsNumber(strcheckck)) { 55 | if (parseInt(strcheckck) > cookiesArr.length) { 56 | console.log('【账号'+strcheckck+'🆔】你哪来那么多账号,没点逼数吗'); 57 | return 58 | } 59 | intcheckckseq = parseInt(strcheckck) - 1; 60 | } 61 | } 62 | console.log("当前查询的CK序号是:"+(intcheckckseq+1)); 63 | 64 | !(async() => { 65 | if (!cookiesArr[intcheckckseq]) { 66 | $.msg($.name, '【提示】请先获取京东账号一cookie\n直接使用NobyDa的京东签到获取', 'https://bean.m.jd.com/bean/signIndex.action', { 67 | "open-url": "https://bean.m.jd.com/bean/signIndex.action" 68 | }); 69 | return; 70 | } 71 | i = intcheckckseq; 72 | 73 | if (cookiesArr[i]) { 74 | cookie = cookiesArr[i]; 75 | $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]); 76 | $.index = i + 1; 77 | $.beanCount = 0; 78 | $.incomeBean = 0; 79 | $.expenseBean = 0; 80 | $.todayIncomeBean = 0; 81 | $.errorMsg = ''; 82 | $.isLogin = true; 83 | $.nickName = ''; 84 | $.message = ''; 85 | $.balance = 0; 86 | $.expiredBalance = 0; 87 | await TotalBean(); 88 | //console.log(`\n********开始【京东账号${$.index}】${$.nickName || $.UserName}******\n`); 89 | if (!$.isLogin) { 90 | console.log(`【提示】cookie已失效,\n请重新登录获取\nhttps://bean.m.jd.com/bean/signIndex.action`); 91 | return; 92 | } 93 | await bean(); 94 | await showMsg(); 95 | 96 | } 97 | allMessage = `【账号🆔${(intcheckckseq+1)}详情统计】收入:${$.todayIncomeBean}京豆\n`+allMessage; 98 | console.log(`${allMessage}`); 99 | 100 | })() 101 | .catch((e) => { 102 | // $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 103 | }) 104 | .finally(() => { 105 | $.done(); 106 | }) 107 | async function showMsg() { 108 | if ($.errorMsg) return 109 | 110 | var arrayObj=Array.from(myMap); 111 | arrayObj.sort(function(a,b){return a[1]-b[1]}) 112 | if(lnShowTop) 113 | allMessage += "【设定了隐藏" +lnShowTop+"豆以下的信息"+"】 "+'\n' 114 | for (var [key, value] of arrayObj) { 115 | /* allMessage += key + ' ---> ' +myMap.get(key)+'京豆\n' */ 116 | if(lnShowTop && lnShowTop>value) 117 | continue; 118 | allMessage += "【" +value+"豆"+"】 "+key+'\n' 119 | } 120 | if(JinQibean) 121 | allMessage += "\n\n【近期豆子】"+JinQibean; 122 | } 123 | function IsNumber(value) { 124 | intPerSent = parseInt(value); 125 | if (!intPerSent) 126 | return false; 127 | else 128 | return true; 129 | } 130 | async function bean() { 131 | // console.log(`北京时间零点时间戳:${parseInt((Date.now() + 28800000) / 86400000) * 86400000 - 28800000}`); 132 | // console.log(`北京时间2020-10-28 06:16:05::${new Date("2020/10/28 06:16:05+08:00").getTime()}`) 133 | // 不管哪个时区。得到都是当前时刻北京时间的时间戳 new Date().getTime() + new Date().getTimezoneOffset()*60*1000 + 8*60*60*1000 134 | 135 | //前一天的0:0:0时间戳 136 | const tm = parseInt((Date.now() + 28800000) / 86400000) * 86400000 - 28800000 - (24 * 60 * 60 * 1000); 137 | // 今天0:0:0时间戳 138 | const tm1 = parseInt((Date.now() + 28800000) / 86400000) * 86400000 - 28800000; 139 | let page = 1, t = 0, todayArr = []; 140 | var strtemp=""; 141 | do { 142 | let response = await getJingBeanBalanceDetail(page); 143 | //console.log(`第${page}页: ${JSON.stringify(response)}`); 144 | if (response && response.code === "0") { 145 | page++; 146 | let detailList = response.jingDetailList; 147 | if (detailList && detailList.length > 0) { 148 | for (let item of detailList) { 149 | if (lnShowJinQiNum-1>-1){ 150 | lnShowJinQiNum--; 151 | strtemp=adjuststring(item.eventMassage); 152 | JinQibean+="\n"+" "+showtime(new Date(item.date))+" "+"【" +item.amount+"豆"+"】"+strtemp 153 | } 154 | 155 | const date = item.date.replace(/-/g, '/') + "+08:00"; 156 | if (new Date(date).getTime() >= tm1 && (!item['eventMassage'].includes("退还") && !item['eventMassage'].includes("物流") && !item['eventMassage'].includes('扣赠'))) { 157 | todayArr.push(item); 158 | } else if (tm > new Date(date).getTime()) { 159 | t = 1; 160 | break; 161 | } 162 | } 163 | } else { 164 | $.errorMsg = `数据异常`; 165 | // $.msg($.name, ``, `账号${$.index}:${$.nickName}\n${$.errorMsg}`); 166 | t = 1; 167 | } 168 | } else if (response && response.code === "3") { 169 | // console.log(`cookie已过期,或者填写不规范,跳出`) 170 | t = 1; 171 | } else { 172 | // console.log(`未知情况:${JSON.stringify(response)}`); 173 | // console.log(`未知情况,跳出`) 174 | t = 1; 175 | } 176 | } while (t === 0); 177 | 178 | for (let item of todayArr) { 179 | if (Number(item.amount) > 0) { 180 | $.todayIncomeBean += Number(item.amount); 181 | strtemp=adjuststring(item.eventMassage); 182 | myMap.set(strtemp,0) 183 | } 184 | } 185 | for (let item of todayArr) { 186 | if (Number(item.amount) > 0) { 187 | strtemp=adjuststring(item.eventMassage); 188 | myMap.set(strtemp,parseInt(myMap.get(strtemp))+parseInt(item.amount)) 189 | } 190 | } 191 | } 192 | 193 | function showtime(date) { 194 | 195 | var timeString = ""; 196 | 197 | if ((date.getHours()) < 10) 198 | timeString += "0" + date.getHours() + ":"; 199 | else 200 | timeString += date.getHours() + ":"; 201 | 202 | if ((date.getMinutes()) < 10) 203 | timeString += "0" + date.getMinutes()+ ":" ; 204 | else 205 | timeString += date.getMinutes()+ ":" ; 206 | 207 | if ((date.getSeconds()) < 10) 208 | timeString += "0" + date.getSeconds(); 209 | else 210 | timeString += date.getSeconds(); 211 | 212 | return timeString; 213 | } 214 | 215 | function TotalBean() { 216 | return new Promise(async resolve => { 217 | const options = { 218 | url: "https://me-api.jd.com/user_new/info/GetJDUserInfoUnion", 219 | headers: { 220 | Host: "me-api.jd.com", 221 | Accept: "*/*", 222 | Connection: "keep-alive", 223 | Cookie: cookie, 224 | "User-Agent": $.isNode() ? (process.env.JD_USER_AGENT ? process.env.JD_USER_AGENT : (require('./USER_AGENTS').USER_AGENT)) : ($.getdata('JDUA') ? $.getdata('JDUA') : "jdapp;iPhone;9.4.4;14.3;network/4g;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1"), 225 | "Accept-Language": "zh-cn", 226 | "Referer": "https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&", 227 | "Accept-Encoding": "gzip, deflate, br" 228 | } 229 | } 230 | $.get(options, (err, resp, data) => { 231 | try { 232 | if (err) { 233 | // $.logErr(err) 234 | } else { 235 | if (data) { 236 | data = JSON.parse(data); 237 | if (data['retcode'] === "1001") { 238 | $.isLogin = false; //cookie过期 239 | return; 240 | } 241 | if (data['retcode'] === "0" && data.data && data.data.hasOwnProperty("userInfo")) { 242 | $.nickName = data.data.userInfo.baseInfo.nickname; 243 | } 244 | if (data['retcode'] === '0' && data.data && data.data['assetInfo']) { 245 | $.beanCount = data.data && data.data['assetInfo']['beanNum']; 246 | } 247 | } else { 248 | $.log('京东服务器返回空数据'); 249 | } 250 | } 251 | } catch (e) { 252 | // $.logErr(e) 253 | } finally { 254 | resolve(); 255 | } 256 | }) 257 | }) 258 | } 259 | function getJingBeanBalanceDetail(page) { 260 | return new Promise(async resolve => { 261 | const options = { 262 | "url": `https://bean.m.jd.com/beanDetail/detail.json?page=${page}`, 263 | "body": `body=${escape(JSON.stringify({"pageSize": "20", "page": page.toString()}))}&appid=ld`, 264 | "headers": { 265 | 'User-Agent': "Mozilla/5.0 (Linux; Android 12; SM-G9880) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Mobile Safari/537.36 EdgA/106.0.1370.47", 266 | 'Content-Type': 'application/x-www-form-urlencoded', 267 | 'Cookie': cookie, 268 | } 269 | } 270 | $.post(options, (err, resp, data) => { 271 | try { 272 | if (err) { 273 | // console.log(`${JSON.stringify(err)}`) 274 | // console.log(`${$.name} API请求失败,请检查网路重试`) 275 | } else { 276 | if (data) { 277 | data = JSON.parse(data); 278 | // console.log(data) 279 | } else { 280 | // console.log(`京东服务器返回空数据`) 281 | } 282 | } 283 | } catch (e) { 284 | // $.logErr(e, resp) 285 | } finally { 286 | resolve(data); 287 | } 288 | }) 289 | }) 290 | } 291 | function queryexpirejingdou() { 292 | return new Promise(async resolve => { 293 | const options = { 294 | "url": `https://wq.jd.com/activep3/singjd/queryexpirejingdou?_=${Date.now()}&g_login_type=1&sceneval=2`, 295 | "headers": { 296 | "Accept": "*/*", 297 | "Accept-Encoding": "gzip, deflate, br", 298 | "Accept-Language": "zh-cn", 299 | "Connection": "keep-alive", 300 | "Cookie": cookie, 301 | "Host": "wq.jd.com", 302 | "Referer": "https://wqs.jd.com/promote/201801/bean/mybean.html", 303 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Mobile/15E148 Safari/604.1" 304 | } 305 | } 306 | $.expirejingdou = 0; 307 | $.get(options, (err, resp, data) => { 308 | try { 309 | if (err) { 310 | // console.log(`${JSON.stringify(err)}`) 311 | // console.log(`${$.name} API请求失败,请检查网路重试`) 312 | } else { 313 | if (data) { 314 | // console.log(data) 315 | data = JSON.parse(data.slice(23, -13)); 316 | // console.log(data) 317 | if (data.ret === 0) { 318 | data['expirejingdou'].map(item => { 319 | // console.log(`${timeFormat(item['time'] * 1000)}日过期京豆:${item['expireamount']}\n`); 320 | $.expirejingdou += item['expireamount']; 321 | }) 322 | // if ($.expirejingdou > 0) { 323 | // $.message += `\n今日将过期:${$.expirejingdou}京豆 🐶`; 324 | // } 325 | } 326 | } else { 327 | // console.log(`京东服务器返回空数据`) 328 | } 329 | } 330 | } catch (e) { 331 | // $.logErr(e, resp) 332 | } finally { 333 | resolve(); 334 | } 335 | }) 336 | }) 337 | } 338 | function jsonParse(str) { 339 | if (typeof str == "string") { 340 | try { 341 | return JSON.parse(str); 342 | } catch (e) { 343 | // console.log(e); 344 | // $.msg($.name, '', '请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie') 345 | return []; 346 | } 347 | } 348 | } 349 | 350 | function adjuststring(streventMassage) { 351 | var strtemp = streventMassage; 352 | strtemp = strtemp.replace("参加[", "").replace("]-奖励", "").replace("]店铺活动-奖励", ""); 353 | strtemp = strtemp.replace("京东自营旗舰店", "(自营)").replace("京东自营官方旗舰店", "(自营官方)"); 354 | strtemp = strtemp.replace("(", "(").replace(")", ")"); 355 | strtemp = strtemp.replace("官方旗舰店", "(官方)"); 356 | strtemp = strtemp.replace("旗舰店", "(旗舰)").replace("专营店", "(专营)").replace("专卖店", "(专卖)"); 357 | strtemp = strtemp.replace("回答京东", "").replace("获取的奖励", ""); 358 | strtemp = strtemp.replace("评价官:", ""); 359 | strtemp = strtemp.replace("商品号:", ""); 360 | strtemp = strtemp.replace("订单号:", ""); 361 | strtemp = strtemp.replace(")奖励京豆", ""); 362 | strtemp = strtemp.replace(")评价官补发奖励京豆", ""); 363 | strtemp = strtemp.replace("PLUS会员使用京东支付银行卡", "PLUS京东支付"); 364 | 365 | return strtemp 366 | } 367 | 368 | function getRemark(strRemark) { 369 | var strTempRemark = ""; 370 | if (strRemark) { 371 | var Tempindex = strRemark.indexOf("@@"); 372 | if (Tempindex != -1) { 373 | var TempRemarkList = strRemark.split("@@"); 374 | strTempRemark=TempRemarkList[0]; 375 | } else{ 376 | strTempRemark=strRemark; 377 | } 378 | } 379 | 380 | return strTempRemark; 381 | } 382 | // prettier-ignore 383 | function Env(t, e) { "undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0); class s { constructor(t) { this.env = t } send(t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise((e, i) => { s.call(this, t, (t, s, r) => { t ? i(t) : e(s) }) }) } get(t) { return this.send.call(this.env, t) } post(t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`) } isNode() { return "undefined" != typeof module && !!module.exports } isQuanX() { return "undefined" != typeof $task } isSurge() { return "undefined" != typeof $httpClient && "undefined" == typeof $loon } isLoon() { return "undefined" != typeof $loon } toObj(t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr(t, e = null) { try { return JSON.stringify(t) } catch { return e } } getjson(t, e) { let s = e; const i = this.getdata(t); if (i) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson(t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript(t) { return new Promise(e => { this.get({ url: t }, (t, s, i) => e(i)) }) } runScript(t, e) { return new Promise(s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r; const [o, h] = i.split("@"), n = { url: `http://${h}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: r }, headers: { "X-Key": o, Accept: "*/*" } }; this.post(n, (t, e, i) => s(i)) }).catch(t => this.logErr(t)) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e); if (!s && !i) return {}; { const i = s ? t : e; try { return JSON.parse(this.fs.readFileSync(i)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e), r = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) } } lodash_get(t, e, s) { const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); let r = t; for (const t of i) if (r = Object(r)[t], void 0 === r) return s; return r } lodash_set(t, e, s) { return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, i) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[i + 1]) >> 0 == +e[i + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) } getdata(t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(t), r = s ? this.getval(s) : ""; if (r) try { const t = JSON.parse(r); e = t ? this.lodash_get(t, i, "") : e } catch (t) { e = "" } } return e } setdata(t, e) { let s = !1; if (/^@/.test(e)) { const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i), h = i ? "null" === o ? null : o || "{}" : "{}"; try { const e = JSON.parse(h); this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i) } catch (e) { const o = {}; this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), i) } } else s = this.setval(t, e); return s } getval(t) { return this.isSurge() || this.isLoon() ? $persistentStore.read(t) : this.isQuanX() ? $prefs.valueForKey(t) : this.isNode() ? (this.data = this.loaddata(), this.data[t]) : this.data && this.data[t] || null } setval(t, e) { return this.isSurge() || this.isLoon() ? $persistentStore.write(t, e) : this.isQuanX() ? $prefs.setValueForKey(t, e) : this.isNode() ? (this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0) : this.data && this.data[e] || null } initGotEnv(t) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) } get(t, e = (() => { })) { t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), this.isSurge() || this.isLoon() ? (this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) })) : this.isQuanX() ? (this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t))) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { try { if (t.headers["set-cookie"]) { const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), e.cookieJar = this.ckjar } } catch (t) { this.logErr(t) } }).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) })) } post(t, e = (() => { })) { if (t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"), t.headers && delete t.headers["Content-Length"], this.isSurge() || this.isLoon()) this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.post(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) }); else if (this.isQuanX()) t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t)); else if (this.isNode()) { this.initGotEnv(t); const { url: s, ...i } = t; this.got.post(s, i).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) }) } } time(t, e = null) { const s = e ? new Date(e) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let e in i) new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? i[e] : ("00" + i[e]).substr(("" + i[e]).length))); return t } msg(e = t, s = "", i = "", r) { const o = t => { if (!t) return t; if ("string" == typeof t) return this.isLoon() ? t : this.isQuanX() ? { "open-url": t } : this.isSurge() ? { url: t } : void 0; if ("object" == typeof t) { if (this.isLoon()) { let e = t.openUrl || t.url || t["open-url"], s = t.mediaUrl || t["media-url"]; return { openUrl: e, mediaUrl: s } } if (this.isQuanX()) { let e = t["open-url"] || t.url || t.openUrl, s = t["media-url"] || t.mediaUrl; return { "open-url": e, "media-url": s } } if (this.isSurge()) { let e = t.url || t.openUrl || t["open-url"]; return { url: e } } } }; if (this.isMute || (this.isSurge() || this.isLoon() ? $notification.post(e, s, i, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) { let t = ["", "==============📣系统通知📣=============="]; t.push(e), s && t.push(s), i && t.push(i), console.log(t.join("\n")), this.logs = this.logs.concat(t) } } log(...t) { t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(t.join(this.logSeparator)) } logErr(t, e) { const s = !this.isSurge() && !this.isQuanX() && !this.isLoon(); s ? this.log("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t) } wait(t) { return new Promise(e => setTimeout(e, t)) } done(t = {}) { const e = (new Date).getTime(), s = (e - this.startTime) / 1e3; this.log("", `🔔${this.name}, 结束! 🕛 ${s} 秒`), this.log(), (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t) } }(t, e) } 384 | -------------------------------------------------------------------------------- /Script/bot_jd_bean_info_QL.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 详细版京东京豆统计 3 | 4 | * 默认不发送通知。 5 | 6 | [task_local] 7 | #京豆详情统计 8 | 20 22 * * * jd_bean_info.js, tag=京豆详情统计, img-url=https://raw.githubusercontent.com/Orz-3/mini/master/Color/jd.png, enabled=true 9 | * */ 10 | const $ = new Env('京豆详情统计'); 11 | const jdCookieNode = $.isNode() ? require('./jdCookie.js') : ''; 12 | let allMessage = ''; 13 | let myMap = new Map(); 14 | let allBean = 0; 15 | let JinQibean=""; 16 | const {getEnvByPtPin} = require('./ql'); 17 | //IOS等用户直接用NobyDa的jd cookie 18 | let cookiesArr = [], cookie = ''; 19 | if ($.isNode()) { 20 | Object.keys(jdCookieNode).forEach((item) => { 21 | cookiesArr.push(jdCookieNode[item]) 22 | }) 23 | if (process.env.JD_DEBUG && process.env.JD_DEBUG === 'false') console.log = () => {}; 24 | } else { 25 | cookiesArr = [$.getdata('CookieJD'), $.getdata('CookieJD2'), ...jsonParse($.getdata('CookiesJD') || "[]").map(item => item.cookie)].filter(item => !!item); 26 | } 27 | 28 | let intcheckckseq=999999; 29 | let strcheckck = process.env.BOTCHECKCODE; 30 | let lnShowTop = 0; 31 | if(!strcheckck){ 32 | console.log("【账号🆔】没有获取到要查询的账号"); 33 | return 34 | } 35 | if ($.isNode() && process.env.BOTShowTopNum) { 36 | lnShowTop = parseInt(process.env.BOTShowTopNum); 37 | } 38 | 39 | let lnShowJinQiNum = 3; 40 | if ($.isNode() && process.env.BOTShowJinQiNum) { 41 | lnShowJinQiNum = parseInt(process.env.BOTShowJinQiNum); 42 | } 43 | 44 | for (i = 0; i < cookiesArr.length; i++) { 45 | if (cookiesArr[i]) { 46 | cookie = cookiesArr[i]; 47 | $.pt_pin = (cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]); 48 | if (strcheckck == $.pt_pin) { 49 | intcheckckseq = i; 50 | break; 51 | } 52 | } 53 | } 54 | 55 | if (intcheckckseq == 999999) { 56 | if (IsNumber(strcheckck)) { 57 | if (parseInt(strcheckck) > cookiesArr.length) { 58 | console.log('【账号'+strcheckck+'🆔】你哪来那么多账号,没点逼数吗'); 59 | return 60 | } 61 | intcheckckseq = parseInt(strcheckck) - 1; 62 | } 63 | } 64 | console.log("当前查询的CK序号是:"+(intcheckckseq+1)); 65 | 66 | !(async() => { 67 | if (!cookiesArr[intcheckckseq]) { 68 | $.msg($.name, '【提示】请先获取京东账号一cookie\n直接使用NobyDa的京东签到获取', 'https://bean.m.jd.com/bean/signIndex.action', { 69 | "open-url": "https://bean.m.jd.com/bean/signIndex.action" 70 | }); 71 | return; 72 | } 73 | i = intcheckckseq; 74 | 75 | if (cookiesArr[i]) { 76 | cookie = cookiesArr[i]; 77 | $.UserName = decodeURIComponent(cookie.match(/pt_pin=([^; ]+)(?=;?)/) && cookie.match(/pt_pin=([^; ]+)(?=;?)/)[1]); 78 | $.index = i + 1; 79 | $.beanCount = 0; 80 | $.incomeBean = 0; 81 | $.expenseBean = 0; 82 | $.todayIncomeBean = 0; 83 | $.errorMsg = ''; 84 | $.isLogin = true; 85 | $.nickName = ''; 86 | $.message = ''; 87 | $.balance = 0; 88 | $.expiredBalance = 0; 89 | await TotalBean(); 90 | //console.log(`\n********开始【京东账号${$.index}】${$.nickName || $.UserName}******\n`); 91 | if (!$.isLogin) { 92 | console.log(`【提示】cookie已失效,\n请重新登录获取\nhttps://bean.m.jd.com/bean/signIndex.action`); 93 | return; 94 | } 95 | await bean(); 96 | await showMsg(); 97 | 98 | } 99 | 100 | var temptest = await getEnvByPtPin($.UserName); 101 | var strRemark=getRemark(temptest.remarks); 102 | if(strRemark) 103 | allMessage = `【账号${(intcheckckseq+1)}详情统计】${strRemark} 收入:${$.todayIncomeBean}京豆\n` +allMessage; 104 | else 105 | allMessage = `【账号${(intcheckckseq+1)}详情统计】收入:${$.todayIncomeBean}京豆\n` +allMessage; 106 | 107 | 108 | console.log(`${allMessage}`); 109 | 110 | })() 111 | .catch((e) => { 112 | // $.log('', `❌ ${$.name}, 失败! 原因: ${e}!`, '') 113 | }) 114 | .finally(() => { 115 | $.done(); 116 | }) 117 | async function showMsg() { 118 | if ($.errorMsg) return 119 | 120 | var arrayObj=Array.from(myMap); 121 | arrayObj.sort(function(a,b){return a[1]-b[1]}) 122 | if(lnShowTop) 123 | allMessage += "【设定了隐藏" +lnShowTop+"豆以下的信息"+"】 "+'\n' 124 | for (var [key, value] of arrayObj) { 125 | /* allMessage += key + ' ---> ' +myMap.get(key)+'京豆\n' */ 126 | if(lnShowTop && lnShowTop>value) 127 | continue; 128 | allMessage += " 【" +value+"豆"+"】 "+key+'\n' 129 | } 130 | if(JinQibean) 131 | allMessage += "\n\n【近期豆子】"+JinQibean; 132 | 133 | } 134 | function IsNumber(value) { 135 | intPerSent = parseInt(value); 136 | if (!intPerSent) 137 | return false; 138 | else 139 | return true; 140 | } 141 | async function bean() { 142 | // console.log(`北京时间零点时间戳:${parseInt((Date.now() + 28800000) / 86400000) * 86400000 - 28800000}`); 143 | // console.log(`北京时间2020-10-28 06:16:05::${new Date("2020/10/28 06:16:05+08:00").getTime()}`) 144 | // 不管哪个时区。得到都是当前时刻北京时间的时间戳 new Date().getTime() + new Date().getTimezoneOffset()*60*1000 + 8*60*60*1000 145 | 146 | //前一天的0:0:0时间戳 147 | const tm = parseInt((Date.now() + 28800000) / 86400000) * 86400000 - 28800000 - (24 * 60 * 60 * 1000); 148 | // 今天0:0:0时间戳 149 | const tm1 = parseInt((Date.now() + 28800000) / 86400000) * 86400000 - 28800000; 150 | let page = 1, t = 0, todayArr = []; 151 | var strtemp=""; 152 | do { 153 | let response = await getJingBeanBalanceDetail(page); 154 | // console.log(`第${page}页: ${JSON.stringify(response)}`); 155 | if (response && response.code === "0") { 156 | page++; 157 | let detailList = response.jingDetailList; 158 | if (detailList && detailList.length > 0) { 159 | for (let item of detailList) { 160 | if (lnShowJinQiNum-1>-1){ 161 | lnShowJinQiNum--; 162 | strtemp=adjuststring(item.eventMassage); 163 | JinQibean+="\n"+" "+showtime(new Date(item.date))+" "+"【" +item.amount+"豆"+"】"+strtemp 164 | } 165 | const date = item.date.replace(/-/g, '/') + "+08:00"; 166 | if (new Date(date).getTime() >= tm1 && (!item['eventMassage'].includes("退还") && !item['eventMassage'].includes("物流") && !item['eventMassage'].includes('扣赠'))) { 167 | todayArr.push(item); 168 | } else if (tm > new Date(date).getTime()) { 169 | t = 1; 170 | break; 171 | } 172 | } 173 | } else { 174 | $.errorMsg = `数据异常`; 175 | // $.msg($.name, ``, `账号${$.index}:${$.nickName}\n${$.errorMsg}`); 176 | t = 1; 177 | } 178 | } else if (response && response.code === "3") { 179 | // console.log(`cookie已过期,或者填写不规范,跳出`) 180 | t = 1; 181 | } else { 182 | // console.log(`未知情况:${JSON.stringify(response)}`); 183 | // console.log(`未知情况,跳出`) 184 | t = 1; 185 | } 186 | } while (t === 0); 187 | 188 | for (let item of todayArr) { 189 | if (Number(item.amount) > 0) { 190 | $.todayIncomeBean += Number(item.amount); 191 | strtemp=adjuststring(item.eventMassage); 192 | myMap.set(strtemp,0) 193 | } 194 | } 195 | for (let item of todayArr) { 196 | if (Number(item.amount) > 0) { 197 | strtemp=adjuststring(item.eventMassage); 198 | myMap.set(strtemp,parseInt(myMap.get(strtemp))+parseInt(item.amount)) 199 | } 200 | } 201 | } 202 | function showtime(date) { 203 | 204 | var timeString = ""; 205 | 206 | if ((date.getHours()) < 10) 207 | timeString += "0" + date.getHours() + ":"; 208 | else 209 | timeString += date.getHours() + ":"; 210 | 211 | if ((date.getMinutes()) < 10) 212 | timeString += "0" + date.getMinutes()+ ":" ; 213 | else 214 | timeString += date.getMinutes()+ ":" ; 215 | 216 | if ((date.getSeconds()) < 10) 217 | timeString += "0" + date.getSeconds(); 218 | else 219 | timeString += date.getSeconds(); 220 | 221 | return timeString; 222 | } 223 | 224 | function TotalBean() { 225 | return new Promise(async resolve => { 226 | const options = { 227 | url: "https://me-api.jd.com/user_new/info/GetJDUserInfoUnion", 228 | headers: { 229 | Host: "me-api.jd.com", 230 | Accept: "*/*", 231 | Connection: "keep-alive", 232 | Cookie: cookie, 233 | "User-Agent": $.isNode() ? (process.env.JD_USER_AGENT ? process.env.JD_USER_AGENT : (require('./USER_AGENTS').USER_AGENT)) : ($.getdata('JDUA') ? $.getdata('JDUA') : "jdapp;iPhone;9.4.4;14.3;network/4g;Mozilla/5.0 (iPhone; CPU iPhone OS 14_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;supportJDSHWK/1"), 234 | "Accept-Language": "zh-cn", 235 | "Referer": "https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&", 236 | "Accept-Encoding": "gzip, deflate, br" 237 | } 238 | } 239 | $.get(options, (err, resp, data) => { 240 | try { 241 | if (err) { 242 | // $.logErr(err) 243 | } else { 244 | if (data) { 245 | data = JSON.parse(data); 246 | if (data['retcode'] === "1001") { 247 | $.isLogin = false; //cookie过期 248 | return; 249 | } 250 | if (data['retcode'] === "0" && data.data && data.data.hasOwnProperty("userInfo")) { 251 | $.nickName = data.data.userInfo.baseInfo.nickname; 252 | } 253 | if (data['retcode'] === '0' && data.data && data.data['assetInfo']) { 254 | $.beanCount = data.data && data.data['assetInfo']['beanNum']; 255 | } 256 | } else { 257 | $.log('京东服务器返回空数据'); 258 | } 259 | } 260 | } catch (e) { 261 | // $.logErr(e) 262 | } finally { 263 | resolve(); 264 | } 265 | }) 266 | }) 267 | } 268 | function getJingBeanBalanceDetail(page) { 269 | return new Promise(async resolve => { 270 | const options = { 271 | "url": `https://bean.m.jd.com/beanDetail/detail.json?page=${page}`, 272 | "body": `body=${escape(JSON.stringify({"pageSize": "20", "page": page.toString()}))}&appid=ld`, 273 | "headers": { 274 | 'User-Agent': "Mozilla/5.0 (Linux; Android 12; SM-G9880) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Mobile Safari/537.36 EdgA/106.0.1370.47", 275 | 'Content-Type': 'application/x-www-form-urlencoded', 276 | 'Cookie': cookie, 277 | } 278 | } 279 | $.post(options, (err, resp, data) => { 280 | try { 281 | if (err) { 282 | // console.log(`${JSON.stringify(err)}`) 283 | // console.log(`${$.name} API请求失败,请检查网路重试`) 284 | } else { 285 | if (data) { 286 | data = JSON.parse(data); 287 | // console.log(data) 288 | } else { 289 | // console.log(`京东服务器返回空数据`) 290 | } 291 | } 292 | } catch (e) { 293 | // $.logErr(e, resp) 294 | } finally { 295 | resolve(data); 296 | } 297 | }) 298 | }) 299 | } 300 | function queryexpirejingdou() { 301 | return new Promise(async resolve => { 302 | const options = { 303 | "url": `https://wq.jd.com/activep3/singjd/queryexpirejingdou?_=${Date.now()}&g_login_type=1&sceneval=2`, 304 | "headers": { 305 | "Accept": "*/*", 306 | "Accept-Encoding": "gzip, deflate, br", 307 | "Accept-Language": "zh-cn", 308 | "Connection": "keep-alive", 309 | "Cookie": cookie, 310 | "Host": "wq.jd.com", 311 | "Referer": "https://wqs.jd.com/promote/201801/bean/mybean.html", 312 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Mobile/15E148 Safari/604.1" 313 | } 314 | } 315 | $.expirejingdou = 0; 316 | $.get(options, (err, resp, data) => { 317 | try { 318 | if (err) { 319 | // console.log(`${JSON.stringify(err)}`) 320 | // console.log(`${$.name} API请求失败,请检查网路重试`) 321 | } else { 322 | if (data) { 323 | // console.log(data) 324 | data = JSON.parse(data.slice(23, -13)); 325 | // console.log(data) 326 | if (data.ret === 0) { 327 | data['expirejingdou'].map(item => { 328 | // console.log(`${timeFormat(item['time'] * 1000)}日过期京豆:${item['expireamount']}\n`); 329 | $.expirejingdou += item['expireamount']; 330 | }) 331 | // if ($.expirejingdou > 0) { 332 | // $.message += `\n今日将过期:${$.expirejingdou}京豆 🐶`; 333 | // } 334 | } 335 | } else { 336 | // console.log(`京东服务器返回空数据`) 337 | } 338 | } 339 | } catch (e) { 340 | // $.logErr(e, resp) 341 | } finally { 342 | resolve(); 343 | } 344 | }) 345 | }) 346 | } 347 | function jsonParse(str) { 348 | if (typeof str == "string") { 349 | try { 350 | return JSON.parse(str); 351 | } catch (e) { 352 | // console.log(e); 353 | // $.msg($.name, '', '请勿随意在BoxJs输入框修改内容\n建议通过脚本去获取cookie') 354 | return []; 355 | } 356 | } 357 | } 358 | 359 | function adjuststring(streventMassage) { 360 | var strtemp = streventMassage; 361 | strtemp = strtemp.replace("参加[", "").replace("]-奖励", "").replace("]店铺活动-奖励", ""); 362 | strtemp = strtemp.replace("京东自营旗舰店", "(自营)").replace("京东自营官方旗舰店", "(自营官方)"); 363 | strtemp = strtemp.replace("(", "(").replace(")", ")"); 364 | strtemp = strtemp.replace("官方旗舰店", "(官方)"); 365 | strtemp = strtemp.replace("旗舰店", "(旗舰)").replace("专营店", "(专营)").replace("专卖店", "(专卖)"); 366 | strtemp = strtemp.replace("回答京东", "").replace("获取的奖励", ""); 367 | strtemp = strtemp.replace("评价官:", ""); 368 | strtemp = strtemp.replace("商品号:", ""); 369 | strtemp = strtemp.replace("订单号:", ""); 370 | strtemp = strtemp.replace(")奖励京豆", ""); 371 | strtemp = strtemp.replace(")评价官补发奖励京豆", ""); 372 | strtemp = strtemp.replace("PLUS会员使用京东支付银行卡", "PLUS京东支付"); 373 | 374 | return strtemp 375 | } 376 | 377 | function getRemark(strRemark) { 378 | var strTempRemark = ""; 379 | if (strRemark) { 380 | var Tempindex = strRemark.indexOf("@@"); 381 | if (Tempindex != -1) { 382 | var TempRemarkList = strRemark.split("@@"); 383 | strTempRemark=TempRemarkList[0]; 384 | } else{ 385 | strTempRemark=strRemark; 386 | } 387 | } 388 | 389 | return strTempRemark; 390 | } 391 | // prettier-ignore 392 | function Env(t, e) { "undefined" != typeof process && JSON.stringify(process.env).indexOf("GITHUB") > -1 && process.exit(0); class s { constructor(t) { this.env = t } send(t, e = "GET") { t = "string" == typeof t ? { url: t } : t; let s = this.get; return "POST" === e && (s = this.post), new Promise((e, i) => { s.call(this, t, (t, s, r) => { t ? i(t) : e(s) }) }) } get(t) { return this.send.call(this.env, t) } post(t) { return this.send.call(this.env, t, "POST") } } return new class { constructor(t, e) { this.name = t, this.http = new s(this), this.data = null, this.dataFile = "box.dat", this.logs = [], this.isMute = !1, this.isNeedRewrite = !1, this.logSeparator = "\n", this.startTime = (new Date).getTime(), Object.assign(this, e), this.log("", `🔔${this.name}, 开始!`) } isNode() { return "undefined" != typeof module && !!module.exports } isQuanX() { return "undefined" != typeof $task } isSurge() { return "undefined" != typeof $httpClient && "undefined" == typeof $loon } isLoon() { return "undefined" != typeof $loon } toObj(t, e = null) { try { return JSON.parse(t) } catch { return e } } toStr(t, e = null) { try { return JSON.stringify(t) } catch { return e } } getjson(t, e) { let s = e; const i = this.getdata(t); if (i) try { s = JSON.parse(this.getdata(t)) } catch { } return s } setjson(t, e) { try { return this.setdata(JSON.stringify(t), e) } catch { return !1 } } getScript(t) { return new Promise(e => { this.get({ url: t }, (t, s, i) => e(i)) }) } runScript(t, e) { return new Promise(s => { let i = this.getdata("@chavy_boxjs_userCfgs.httpapi"); i = i ? i.replace(/\n/g, "").trim() : i; let r = this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout"); r = r ? 1 * r : 20, r = e && e.timeout ? e.timeout : r; const [o, h] = i.split("@"), n = { url: `http://${h}/v1/scripting/evaluate`, body: { script_text: t, mock_type: "cron", timeout: r }, headers: { "X-Key": o, Accept: "*/*" } }; this.post(n, (t, e, i) => s(i)) }).catch(t => this.logErr(t)) } loaddata() { if (!this.isNode()) return {}; { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e); if (!s && !i) return {}; { const i = s ? t : e; try { return JSON.parse(this.fs.readFileSync(i)) } catch (t) { return {} } } } } writedata() { if (this.isNode()) { this.fs = this.fs ? this.fs : require("fs"), this.path = this.path ? this.path : require("path"); const t = this.path.resolve(this.dataFile), e = this.path.resolve(process.cwd(), this.dataFile), s = this.fs.existsSync(t), i = !s && this.fs.existsSync(e), r = JSON.stringify(this.data); s ? this.fs.writeFileSync(t, r) : i ? this.fs.writeFileSync(e, r) : this.fs.writeFileSync(t, r) } } lodash_get(t, e, s) { const i = e.replace(/\[(\d+)\]/g, ".$1").split("."); let r = t; for (const t of i) if (r = Object(r)[t], void 0 === r) return s; return r } lodash_set(t, e, s) { return Object(t) !== t ? t : (Array.isArray(e) || (e = e.toString().match(/[^.[\]]+/g) || []), e.slice(0, -1).reduce((t, s, i) => Object(t[s]) === t[s] ? t[s] : t[s] = Math.abs(e[i + 1]) >> 0 == +e[i + 1] ? [] : {}, t)[e[e.length - 1]] = s, t) } getdata(t) { let e = this.getval(t); if (/^@/.test(t)) { const [, s, i] = /^@(.*?)\.(.*?)$/.exec(t), r = s ? this.getval(s) : ""; if (r) try { const t = JSON.parse(r); e = t ? this.lodash_get(t, i, "") : e } catch (t) { e = "" } } return e } setdata(t, e) { let s = !1; if (/^@/.test(e)) { const [, i, r] = /^@(.*?)\.(.*?)$/.exec(e), o = this.getval(i), h = i ? "null" === o ? null : o || "{}" : "{}"; try { const e = JSON.parse(h); this.lodash_set(e, r, t), s = this.setval(JSON.stringify(e), i) } catch (e) { const o = {}; this.lodash_set(o, r, t), s = this.setval(JSON.stringify(o), i) } } else s = this.setval(t, e); return s } getval(t) { return this.isSurge() || this.isLoon() ? $persistentStore.read(t) : this.isQuanX() ? $prefs.valueForKey(t) : this.isNode() ? (this.data = this.loaddata(), this.data[t]) : this.data && this.data[t] || null } setval(t, e) { return this.isSurge() || this.isLoon() ? $persistentStore.write(t, e) : this.isQuanX() ? $prefs.setValueForKey(t, e) : this.isNode() ? (this.data = this.loaddata(), this.data[e] = t, this.writedata(), !0) : this.data && this.data[e] || null } initGotEnv(t) { this.got = this.got ? this.got : require("got"), this.cktough = this.cktough ? this.cktough : require("tough-cookie"), this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar, t && (t.headers = t.headers ? t.headers : {}, void 0 === t.headers.Cookie && void 0 === t.cookieJar && (t.cookieJar = this.ckjar)) } get(t, e = (() => { })) { t.headers && (delete t.headers["Content-Type"], delete t.headers["Content-Length"]), this.isSurge() || this.isLoon() ? (this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.get(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) })) : this.isQuanX() ? (this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t))) : this.isNode() && (this.initGotEnv(t), this.got(t).on("redirect", (t, e) => { try { if (t.headers["set-cookie"]) { const s = t.headers["set-cookie"].map(this.cktough.Cookie.parse).toString(); s && this.ckjar.setCookieSync(s, null), e.cookieJar = this.ckjar } } catch (t) { this.logErr(t) } }).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) })) } post(t, e = (() => { })) { if (t.body && t.headers && !t.headers["Content-Type"] && (t.headers["Content-Type"] = "application/x-www-form-urlencoded"), t.headers && delete t.headers["Content-Length"], this.isSurge() || this.isLoon()) this.isSurge() && this.isNeedRewrite && (t.headers = t.headers || {}, Object.assign(t.headers, { "X-Surge-Skip-Scripting": !1 })), $httpClient.post(t, (t, s, i) => { !t && s && (s.body = i, s.statusCode = s.status), e(t, s, i) }); else if (this.isQuanX()) t.method = "POST", this.isNeedRewrite && (t.opts = t.opts || {}, Object.assign(t.opts, { hints: !1 })), $task.fetch(t).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => e(t)); else if (this.isNode()) { this.initGotEnv(t); const { url: s, ...i } = t; this.got.post(s, i).then(t => { const { statusCode: s, statusCode: i, headers: r, body: o } = t; e(null, { status: s, statusCode: i, headers: r, body: o }, o) }, t => { const { message: s, response: i } = t; e(s, i, i && i.body) }) } } time(t, e = null) { const s = e ? new Date(e) : new Date; let i = { "M+": s.getMonth() + 1, "d+": s.getDate(), "H+": s.getHours(), "m+": s.getMinutes(), "s+": s.getSeconds(), "q+": Math.floor((s.getMonth() + 3) / 3), S: s.getMilliseconds() }; /(y+)/.test(t) && (t = t.replace(RegExp.$1, (s.getFullYear() + "").substr(4 - RegExp.$1.length))); for (let e in i) new RegExp("(" + e + ")").test(t) && (t = t.replace(RegExp.$1, 1 == RegExp.$1.length ? i[e] : ("00" + i[e]).substr(("" + i[e]).length))); return t } msg(e = t, s = "", i = "", r) { const o = t => { if (!t) return t; if ("string" == typeof t) return this.isLoon() ? t : this.isQuanX() ? { "open-url": t } : this.isSurge() ? { url: t } : void 0; if ("object" == typeof t) { if (this.isLoon()) { let e = t.openUrl || t.url || t["open-url"], s = t.mediaUrl || t["media-url"]; return { openUrl: e, mediaUrl: s } } if (this.isQuanX()) { let e = t["open-url"] || t.url || t.openUrl, s = t["media-url"] || t.mediaUrl; return { "open-url": e, "media-url": s } } if (this.isSurge()) { let e = t.url || t.openUrl || t["open-url"]; return { url: e } } } }; if (this.isMute || (this.isSurge() || this.isLoon() ? $notification.post(e, s, i, o(r)) : this.isQuanX() && $notify(e, s, i, o(r))), !this.isMuteLog) { let t = ["", "==============📣系统通知📣=============="]; t.push(e), s && t.push(s), i && t.push(i), console.log(t.join("\n")), this.logs = this.logs.concat(t) } } log(...t) { t.length > 0 && (this.logs = [...this.logs, ...t]), console.log(t.join(this.logSeparator)) } logErr(t, e) { const s = !this.isSurge() && !this.isQuanX() && !this.isLoon(); s ? this.log("", `❗️${this.name}, 错误!`, t.stack) : this.log("", `❗️${this.name}, 错误!`, t) } wait(t) { return new Promise(e => setTimeout(e, t)) } done(t = {}) { const e = (new Date).getTime(), s = (e - this.startTime) / 1e3; this.log("", `🔔${this.name}, 结束! 🕛 ${s} 秒`), this.log(), (this.isSurge() || this.isQuanX() || this.isLoon()) && $done(t) } }(t, e) } 393 | -------------------------------------------------------------------------------- /config/ccbotSetting.json: -------------------------------------------------------------------------------- 1 | { 2 | "bd命令配置": { 3 | "说明1": "bd命令: bd 1 或 bd ptpin,返回当天京豆收入详情", 4 | "说明2": "setbd命令: setbd 20,设定隐藏指定数量以下的京豆详情", 5 | "说明3": "bot_jd_bean_info_QL显示账号及备注名,bot_jd_bean_info不显示", 6 | "脚本文件地址": "/ql/repo/ccwav_QLScript2/bot_jd_bean_info_QL.js", 7 | "近期京豆展示的条数":"3", 8 | "多少秒后自动删除": "30" 9 | }, 10 | "cb命令配置": { 11 | "说明1": "cb命令: cb 1 或 cb ptpin,返回当天资产详情", 12 | "说明2": "此配置与非全局的/ccbean 命令共享", 13 | "说明3": "可以选择关闭的项目有: 过期京豆&汪汪赛跑&查优惠券&汪汪乐园&京东赚赚&京东秒杀&东东农场&极速金币&京喜牧场&京喜工厂&喜豆查询&京东工厂&领现金&金融养猪&东东萌宠", 14 | "脚本文件地址": "/ql/repo/ccwav_QLScript2/bot_jd_bean_change_QL.js", 15 | "关闭查询项目": "过期京豆&汪汪乐园&京东赚赚&东东农场&极速金币&京喜牧场&京喜工厂&京东工厂&领现金&金融养猪&喜豆查询", 16 | "多少秒后自动删除": "30" 17 | }, 18 | "jf命令配置": { 19 | "说明1": "jf命令: jf 1 ,返回当天京粉详情", 20 | "多少秒后自动删除": "30" 21 | }, 22 | "天气命令配置": { 23 | "说明1": "命令: 地区天气,如深圳天气 ,返回最近天气详情", 24 | "多少秒后自动删除": "30" 25 | }, 26 | "路由器命令配置": { 27 | "说明1": "发送/routerinfo 给机器人查询路由器ip等信息", 28 | "说明2": "发送/routerip 给机器人通知路由器重新拨号换IP", 29 | "查询信息脚本文件地址": "/ql/scripts/AutoRun/Routerinfo.js", 30 | "重拨路由脚本文件地址": "/ql/scripts/AutoRun/RouterResetIP.js" 31 | }, 32 | "文件存放配置": [ 33 | { 34 | "按钮名字": "配置档", 35 | "每行按钮数": "3" 36 | },{ 37 | "按钮名字": "放入config", 38 | "备份原脚本": "1", 39 | "不问是否定时":"1", 40 | "存放路径": "/ql/config" 41 | }, 42 | { 43 | "按钮名字": "放入scripts", 44 | "备份原脚本": "1", 45 | "存放路径": "/ql/scripts" 46 | }, 47 | { 48 | "按钮名字": "放入parse并执行", 49 | "备份原脚本": "0", 50 | "存放路径": "/ql/scripts/parse/jd", 51 | "不问是否定时":"1", 52 | "执行命令1": "task qitoCreat.js", 53 | "执行命令2": "task 文件名" 54 | }, 55 | { 56 | "按钮名字": "放入AutoRun", 57 | "备份原脚本": "0", 58 | "不问是否定时":"1", 59 | "存放路径": "/ql/scripts/AutoRun" 60 | }, 61 | { 62 | "按钮名字": "放入scripts并执行", 63 | "备份原脚本": "1", 64 | "存放路径": "task /ql/scripts" 65 | } 66 | ] 67 | } 68 | -------------------------------------------------------------------------------- /jbot/bot/bean.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageFont, ImageDraw 2 | from telethon import events, Button 3 | from .. import LOG_DIR, jdbot, chat_id, BOT_SET, BOT_DIR, logger, ch_name 4 | from prettytable import PrettyTable 5 | import subprocess 6 | from .beandata import get_bean_data 7 | from .utils import V4,split_list, press_event 8 | 9 | BEAN_IN_FILE = f'{LOG_DIR}/bean_income.csv' 10 | BEAN_OUT_FILE = f'{LOG_DIR}/bean_outlay.csv' 11 | BEAN_TOTAL_FILE = f'{LOG_DIR}/bean_total.csv' 12 | BEAN_IMG = f'{LOG_DIR}/bean.jpg' 13 | FONT_FILE = f'{BOT_DIR}/font/jet.ttf' 14 | 15 | 16 | @jdbot.on(events.NewMessage(chats=chat_id, pattern=r'^/bean')) 17 | async def bot_bean(event): 18 | msg_text = event.raw_text.split(' ') 19 | try: 20 | msg = await jdbot.send_message(chat_id, '正在查询,请稍后') 21 | if isinstance(msg_text, list) and len(msg_text) == 2: 22 | text = msg_text[-1] 23 | else: 24 | text = None 25 | 26 | if text==None: 27 | SENDER = event.sender_id 28 | btn = [] 29 | for i in range(11): 30 | btn.append(Button.inline(str(i+1), data=str(i+1))) 31 | btn.append(Button.inline('取消', data='cancel')) 32 | btn = split_list(btn, 3) 33 | async with jdbot.conversation(SENDER, timeout=90) as conv: 34 | info='请选择要查询的账号:' 35 | msg = await jdbot.edit_message(msg, info, buttons=btn, link_preview=False) 36 | convdata = await conv.wait_event(press_event(SENDER)) 37 | res = bytes.decode(convdata.data) 38 | if res == 'cancel': 39 | msg = await jdbot.edit_message(msg, '对话已取消') 40 | conv.cancel() 41 | else: 42 | text = res 43 | msg = await jdbot.edit_message(msg, '开始查询账号'+text+'的资产,请稍后...') 44 | if text==None: 45 | await jdbot.delete_messages(chat_id, msg) 46 | return 47 | 48 | if V4 and text == 'in': 49 | subprocess.check_output( 50 | 'jcsv', shell=True, stderr=subprocess.STDOUT) 51 | creat_bean_counts(BEAN_IN_FILE) 52 | await jdbot.delete_messages(chat_id, msg) 53 | await jdbot.send_message(chat_id, '您的近日收入情况', file=BEAN_IMG) 54 | elif V4 and text == 'out': 55 | subprocess.check_output( 56 | 'jcsv', shell=True, stderr=subprocess.STDOUT) 57 | creat_bean_counts(BEAN_OUT_FILE) 58 | await jdbot.delete_messages(chat_id, msg) 59 | await jdbot.send_message(chat_id, '您的近日支出情况', file=BEAN_IMG) 60 | elif not V4 and (text == 'in' or text == 'out' or text is None): 61 | await jdbot.edit_message(msg, 'QL暂不支持使用bean in、out ,请使用/bean n n为数字') 62 | elif text and int(text): 63 | res = get_bean_data(int(text)) 64 | if res['code'] != 200: 65 | await jdbot.delete_messages(chat_id, msg) 66 | await jdbot.send_message(chat_id, f'something wrong,I\'m sorry\n{str(res["data"])}') 67 | else: 68 | creat_bean_count(res['data'][3], res['data'] 69 | [0], res['data'][1], res['data'][2][1:]) 70 | await jdbot.delete_messages(chat_id, msg) 71 | await jdbot.send_message(chat_id, f'您的账号{text}收支情况', file=BEAN_IMG) 72 | elif not text: 73 | subprocess.check_output( 74 | 'jcsv', shell=True, stderr=subprocess.STDOUT) 75 | creat_bean_counts(BEAN_TOTAL_FILE) 76 | await jdbot.delete_messages(chat_id, msg) 77 | await jdbot.send_message(chat_id, '您的总京豆情况', file=BEAN_IMG) 78 | else: 79 | await jdbot.delete_messages(chat_id, msg) 80 | await jdbot.send_message(chat_id, '青龙暂仅支持/bean n n为账号数字') 81 | except Exception as e: 82 | await jdbot.send_message(chat_id, f'something wrong,I\'m sorry\n{str(e)}') 83 | logger.error(f'something wrong,I\'m sorry{str(e)}') 84 | 85 | if ch_name: 86 | jdbot.add_event_handler(bot_bean, events.NewMessage( 87 | chats=chat_id, pattern=BOT_SET['命令别名']['bean'])) 88 | 89 | 90 | def creat_bean_count(date, beansin, beansout, beanstotal): 91 | tb = PrettyTable() 92 | tb.add_column('DATE', date) 93 | tb.add_column('BEANSIN', beansin) 94 | tb.add_column('BEANSOUT', beansout) 95 | tb.add_column('TOTAL', beanstotal) 96 | font = ImageFont.truetype(FONT_FILE, 18) 97 | im = Image.new("RGB", (500, 260), (244, 244, 244)) 98 | dr = ImageDraw.Draw(im) 99 | dr.text((10, 5), str(tb), font=font, fill="#000000") 100 | im.save(BEAN_IMG) 101 | 102 | 103 | def creat_bean_counts(csv_file): 104 | with open(csv_file, 'r', encoding='utf-8') as f: 105 | data = f.readlines() 106 | tb = PrettyTable() 107 | num = len(data[-1].split(',')) - 1 108 | title = ['DATE'] 109 | for i in range(0, num): 110 | title.append('COUNT'+str(i+1)) 111 | tb.field_names = title 112 | data = data[-7:] 113 | for line in data: 114 | row = line.split(',') 115 | if len(row) > len(title): 116 | row = row[:len(title)] 117 | elif len(row) < len(title): 118 | i = len(title) - len(row) 119 | for _ in range(0, i): 120 | row.append(str(0)) 121 | tb.add_row(row) 122 | length = 172 + 100 * num 123 | im = Image.new("RGB", (length, 400), (244, 244, 244)) 124 | dr = ImageDraw.Draw(im) 125 | font = ImageFont.truetype(FONT_FILE, 18) 126 | dr.text((10, 5), str(tb), font=font, fill="#000000") 127 | im.save(BEAN_IMG) 128 | -------------------------------------------------------------------------------- /jbot/bot/beandata.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import datetime 3 | import time 4 | import json 5 | from datetime import timedelta 6 | from datetime import timezone 7 | from .utils import CONFIG_SH_FILE, get_cks, AUTH_FILE, QL,logger 8 | SHA_TZ = timezone( 9 | timedelta(hours=8), 10 | name='Asia/Shanghai', 11 | ) 12 | requests.adapters.DEFAULT_RETRIES = 5 13 | session = requests.session() 14 | session.keep_alive = False 15 | 16 | url = "https://api.m.jd.com/api" 17 | 18 | 19 | def gen_body(page): 20 | body = { 21 | "beginDate": datetime.datetime.utcnow().replace(tzinfo=timezone.utc).astimezone(SHA_TZ).strftime("%Y-%m-%d %H:%M:%S"), 22 | "endDate": datetime.datetime.utcnow().replace(tzinfo=timezone.utc).astimezone(SHA_TZ).strftime("%Y-%m-%d %H:%M:%S"), 23 | "pageNo": page, 24 | "pageSize": 20, 25 | } 26 | return body 27 | 28 | 29 | def gen_params(page): 30 | body = gen_body(page) 31 | params = { 32 | "functionId": "jposTradeQuery", 33 | "appid": "swat_miniprogram", 34 | "client": "tjj_m", 35 | "sdkName": "orderDetail", 36 | "sdkVersion": "1.0.0", 37 | "clientVersion": "3.1.3", 38 | "timestamp": int(round(time.time() * 1000)), 39 | "body": json.dumps(body) 40 | } 41 | return params 42 | 43 | def get_beans_7days(ck): 44 | try: 45 | day_7 = True 46 | page = 0 47 | headers = { 48 | "Content-Type": "application/x-www-form-urlencoded;", 49 | "User-Agent": "Mozilla/5.0 (Linux; Android 12; SM-G9880) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Mobile Safari/537.36 EdgA/106.0.1370.47", 50 | "Cookie": ck 51 | } 52 | days = [] 53 | for i in range(0, 7): 54 | days.append( 55 | (datetime.date.today() - datetime.timedelta(days=i)).strftime("%Y-%m-%d")) 56 | beans_in = {key: 0 for key in days} 57 | beans_out = {key: 0 for key in days} 58 | 59 | while day_7: 60 | page = page + 1 61 | url="https://bean.m.jd.com/beanDetail/detail.json?page="+str(page) 62 | resp = session.get(url,headers=headers, timeout=100).text 63 | amount=0 64 | res = json.loads(resp) 65 | if res['code'] == "0": 66 | for i in res['jingDetailList']: 67 | amount=int(i['amount']) 68 | for date in days: 69 | if str(date) in i['date'] and amount > 0: 70 | beans_in[str(date)] = beans_in[str( 71 | date)] + amount 72 | break 73 | elif str(date) in i['date'] and amount < 0: 74 | beans_out[str(date)] = beans_out[str( 75 | date)] + amount 76 | break 77 | if i['date'].split(' ')[0] not in str(days): 78 | day_7 = False 79 | else: 80 | return {'code': 400, 'data': res} 81 | return {'code': 200, 'data': [beans_in, beans_out, days]} 82 | except Exception as e: 83 | logger.error(str(e)) 84 | return {'code': 400, 'data': str(e)} 85 | 86 | def get_total_beans(ck): 87 | try: 88 | headers = { 89 | "Accept": "application/json,text/plain, */*", 90 | "Content-Type": "application/x-www-form-urlencoded", 91 | "Accept-Encoding": "gzip, deflate, br", 92 | "Accept-Language": "zh-cn", 93 | "Connection": "keep-alive", 94 | "Cookie": ck, 95 | "Referer": "https://wqs.jd.com/my/jingdou/my.shtml?sceneval=2", 96 | "User-Agent": "Mozilla/5.0 (Linux; Android 12; SM-G9880) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Mobile Safari/537.36 EdgA/106.0.1370.47" 97 | } 98 | jurl = "https://wq.jd.com/user/info/QueryJDUserInfo?sceneval=2" 99 | resp = session.get(jurl, headers=headers, timeout=100).text 100 | res = json.loads(resp) 101 | return res['base']['jdNum'],res['base']['nickname'],'http://storage.360buyimg.com/i.imageUpload/b6adc6e4bbaa31363437393935323238323435_mid.jpg' 102 | except Exception as e: 103 | logger.error(str(e)) 104 | 105 | def get_bean_data(i): 106 | try: 107 | if QL: 108 | ckfile = AUTH_FILE 109 | else: 110 | ckfile = CONFIG_SH_FILE 111 | cookies = get_cks(ckfile) 112 | if cookies: 113 | ck = cookies[i-1] 114 | beans_res = get_beans_7days(ck) 115 | beantotal,nickname,pic = get_total_beans(ck) 116 | if beans_res['code'] != 200: 117 | return beans_res 118 | else: 119 | beans_in, beans_out = [], [] 120 | beanstotal = [int(beantotal), ] 121 | for i in beans_res['data'][0]: 122 | beantotal = int( 123 | beantotal) - int(beans_res['data'][0][i]) - int(beans_res['data'][1][i]) 124 | beans_in.append(int(beans_res['data'][0][i])) 125 | beans_out.append(int(str(beans_res['data'][1][i]).replace('-', ''))) 126 | beanstotal.append(beantotal) 127 | return {'code': 200, 'data': [beans_in[::-1], beans_out[::-1], beanstotal[::-1], beans_res['data'][2][::-1],nickname,pic]} 128 | except Exception as e: 129 | logger.error(str(e)) -------------------------------------------------------------------------------- /jbot/bot/chart.py: -------------------------------------------------------------------------------- 1 | from telethon import events, Button 2 | from .. import jdbot, chat_id, LOG_DIR, logger, BOT_SET, ch_name 3 | from ..bot.quickchart import QuickChart 4 | from .beandata import get_bean_data 5 | from .utils import V4,split_list, press_event 6 | BEAN_IMG = f'{LOG_DIR}/bot/bean.jpeg' 7 | 8 | 9 | @jdbot.on(events.NewMessage(chats=chat_id, pattern=r'^/chart')) 10 | async def my_chart(event): 11 | msg_text = event.raw_text.split(' ') 12 | msg = await jdbot.send_message(chat_id, '正在查询,请稍后') 13 | try: 14 | if isinstance(msg_text, list) and len(msg_text) == 2: 15 | text = msg_text[-1] 16 | else: 17 | text = None 18 | 19 | if text==None: 20 | SENDER = event.sender_id 21 | btn = [] 22 | for i in range(11): 23 | btn.append(Button.inline(str(i+1), data=str(i+1))) 24 | btn.append(Button.inline('取消', data='cancel')) 25 | btn = split_list(btn, 3) 26 | async with jdbot.conversation(SENDER, timeout=90) as conv: 27 | info='请选择要查询的账号:' 28 | msg = await jdbot.edit_message(msg, info, buttons=btn, link_preview=False) 29 | convdata = await conv.wait_event(press_event(SENDER)) 30 | res = bytes.decode(convdata.data) 31 | if res == 'cancel': 32 | msg = await jdbot.edit_message(msg, '对话已取消') 33 | conv.cancel() 34 | else: 35 | text = res 36 | msg = await jdbot.edit_message(msg, '开始查询账号'+text+'的资产,请稍后...') 37 | if text==None: 38 | await jdbot.delete_messages(chat_id, msg) 39 | return 40 | 41 | if text and int(text): 42 | res = get_bean_data(int(text)) 43 | if res['code'] != 200: 44 | msg = await jdbot.edit_message(msg, f'something wrong,I\'m sorry\n{str(res["data"])}') 45 | else: 46 | creat_chart(res['data'][3], f'账号{str(text)}', 47 | res['data'][0], res['data'][1], res['data'][2][1:]) 48 | await jdbot.delete_messages(chat_id, msg) 49 | msg = await jdbot.send_message(chat_id, f'您的账号{text}收支情况', file=BEAN_IMG) 50 | else: 51 | msg = await jdbot.edit_message(msg, '请正确使用命令\n/chart n n为第n个账号') 52 | except Exception as e: 53 | await jdbot.edit_message(msg, f'something wrong,I\'m sorry\n{str(e)}') 54 | logger.error(f'something wrong,I\'m sorry\n{str(e)}') 55 | 56 | if ch_name: 57 | jdbot.add_event_handler(my_chart, events.NewMessage( 58 | chats=chat_id, pattern=BOT_SET['命令别名']['chart'])) 59 | 60 | 61 | def creat_chart(xdata, title, bardata, bardata2, linedate): 62 | qc = QuickChart() 63 | qc.background_color = '#fff' 64 | qc.width = "1000" 65 | qc.height = "600" 66 | qc.config = { 67 | "type": "bar", 68 | "data": { 69 | "labels": xdata, 70 | "datasets": [ 71 | { 72 | "label": "IN", 73 | "backgroundColor": [ 74 | "rgb(255, 99, 132)", 75 | "rgb(255, 159, 64)", 76 | "rgb(255, 205, 86)", 77 | "rgb(75, 192, 192)", 78 | "rgb(54, 162, 235)", 79 | "rgb(153, 102, 255)", 80 | "rgb(255, 99, 132)" 81 | ], 82 | "yAxisID": "y1", 83 | "data": bardata 84 | }, 85 | { 86 | "label": "OUT", 87 | "backgroundColor": [ 88 | "rgb(255, 99, 132)", 89 | "rgb(255, 159, 64)", 90 | "rgb(255, 205, 86)", 91 | "rgb(75, 192, 192)", 92 | "rgb(54, 162, 235)", 93 | "rgb(153, 102, 255)", 94 | "rgb(255, 99, 132)" 95 | ], 96 | "yAxisID": "y1", 97 | "data": bardata2 98 | }, 99 | { 100 | "label": "TOTAL", 101 | "type": "line", 102 | "fill": False, 103 | "backgroundColor": "rgb(201, 203, 207)", 104 | "yAxisID": "y2", 105 | "data": linedate 106 | } 107 | ] 108 | }, 109 | "options": { 110 | "plugins": { 111 | "datalabels": { 112 | "anchor": 'end', 113 | "align": -100, 114 | "color": '#666', 115 | "font": { 116 | "size": 20, 117 | } 118 | }, 119 | }, 120 | "legend": { 121 | "labels": { 122 | "fontSize": 20, 123 | "fontStyle": 'bold', 124 | } 125 | }, 126 | "title": { 127 | "display": True, 128 | "text": f'{title} 收支情况', 129 | "fontSize": 24, 130 | }, 131 | "scales": { 132 | "xAxes": [{ 133 | "ticks": { 134 | "fontSize": 24, 135 | } 136 | }], 137 | "yAxes": [ 138 | { 139 | "id": "y1", 140 | "type": "linear", 141 | "display": False, 142 | "position": "left", 143 | "ticks": { 144 | "max": int(int(max([max(bardata), max(bardata2)])+100)*2) 145 | }, 146 | "scaleLabel": { 147 | "fontSize": 20, 148 | "fontStyle": 'bold', 149 | } 150 | }, 151 | { 152 | "id": "y2", 153 | "type": "linear", 154 | "display": False, 155 | "ticks": { 156 | "min": int(min(linedate)*2-(max(linedate))-100), 157 | "max": int(int(max(linedate))) 158 | }, 159 | "position": "right" 160 | } 161 | ] 162 | } 163 | } 164 | } 165 | qc.to_file(BEAN_IMG) 166 | -------------------------------------------------------------------------------- /jbot/bot/getfile.py: -------------------------------------------------------------------------------- 1 | from telethon import events, Button 2 | from asyncio import exceptions 3 | from .. import jdbot, chat_id, SCRIPTS_DIR, CONFIG_DIR, logger 4 | from .utils import press_event, backup_file, Remove_file, add_cron, cmd, DIY_DIR, TASK_CMD, split_list 5 | import json 6 | import os 7 | 8 | @jdbot.on(events.NewMessage(from_users=chat_id)) 9 | async def bot_get_file(event): 10 | """定义文件操作""" 11 | try: 12 | btn = [] 13 | issetconfig=False 14 | 15 | if os.path.exists("/ql/data/config/auth.json"): 16 | configpath="/ql/data/" 17 | 18 | if os.path.exists("/ql/config/auth.json"): 19 | configpath="/ql/" 20 | 21 | if os.path.exists("/jd/config/config.sh"): 22 | configpath="/jd/" 23 | 24 | try: 25 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 26 | ccbotSetting = json.loads(f.read()) 27 | f.close() 28 | for key in ccbotSetting: 29 | if key=="文件存放配置": 30 | issetconfig=True 31 | except Exception as e: 32 | await jdbot.send_message(chat_id,f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 33 | return 34 | 35 | if not issetconfig: 36 | await jdbot.send_message(chat_id,f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 37 | return 38 | 39 | getfileSettinglist=ccbotSetting["文件存放配置"] 40 | 41 | countbtn=3 42 | for fileSetting in getfileSettinglist: 43 | if fileSetting["按钮名字"]=="配置档": 44 | countbtn=int(fileSetting["每行按钮数"]) 45 | else: 46 | btn.append(Button.inline(fileSetting["按钮名字"], data=fileSetting["按钮名字"]+"|"+fileSetting["存放路径"])) 47 | btn.append(Button.inline('取消', data='取消|cancel')) 48 | btn = split_list(btn, countbtn) 49 | 50 | SENDER = event.sender_id 51 | if event.message.file: 52 | markup = [] 53 | filename = event.message.file.name 54 | cmdtext = None 55 | runcmd = "" 56 | async with jdbot.conversation(SENDER, timeout=180) as conv: 57 | msg = await conv.send_message('请选择您要放入的文件夹或操作:\n') 58 | markup = btn 59 | 60 | msg = await jdbot.edit_message(msg, '请选择您要放入的文件夹或操作:', buttons=markup) 61 | convdata = await conv.wait_event(press_event(SENDER)) 62 | 63 | res = bytes.decode(convdata.data) 64 | isbackup="1" 65 | noaskaddcron="0" 66 | 67 | for fileSetting in getfileSettinglist: 68 | if fileSetting["按钮名字"]=="配置档": 69 | continue 70 | if fileSetting["按钮名字"]==res.split("|")[0]: 71 | isbackup=fileSetting["备份原脚本"] 72 | for key in fileSetting: 73 | if "执行命令" in key: 74 | if runcmd!="" : 75 | runcmd=runcmd+"\n" 76 | runcmd=runcmd+fileSetting[key].replace("文件名",filename) 77 | if "不问是否定时" in key: 78 | noaskaddcron=fileSetting[key] 79 | isrun="0" 80 | res=res.split("|")[1] 81 | if "task " in res: 82 | isrun="1" 83 | res=res.replace("task ","") 84 | 85 | markup = [Button.inline('是', data='yes'), 86 | Button.inline('否', data='no')] 87 | if res == 'cancel': 88 | msg = await jdbot.edit_message(msg, '对话已取消') 89 | conv.cancel() 90 | else: 91 | res2="" 92 | if noaskaddcron=="0": 93 | msg = await jdbot.edit_message(msg, '是否尝试自动加入定时', buttons=markup) 94 | convdata2 = await conv.wait_event(press_event(SENDER)) 95 | res2 = bytes.decode(convdata2.data) 96 | 97 | if isbackup=="1": 98 | backup_file(f'{res}/{filename}') 99 | else: 100 | Remove_file(f'{res}/{filename}') 101 | 102 | if isrun=="1": 103 | cmdtext = f'{TASK_CMD} {res}/{filename} now' 104 | await jdbot.download_media(event.message, res) 105 | with open(f'{res}/{filename}', 'r', encoding='utf-8') as f: 106 | resp = f.read() 107 | 108 | if res2 == 'yes': 109 | await add_cron(jdbot, conv, resp, filename, msg, SENDER, markup, res) 110 | else: 111 | await jdbot.edit_message(msg, f'{filename}已保存到{res}文件夹') 112 | conv.cancel() 113 | if cmdtext: 114 | if runcmd!="": 115 | runcmd=cmdtext+"\n"+runcmd 116 | else: 117 | runcmd=cmdtext 118 | 119 | if runcmd!="": 120 | msg=await jdbot.send_message(chat_id,"开始执行命令列表"+":\n"+runcmd) 121 | cmdlist=runcmd.split("\n") 122 | for RunCommound in cmdlist: 123 | await cmd(RunCommound) 124 | 125 | await jdbot.edit_message(msg, '任务执行完毕,祝君愉快.') 126 | 127 | except exceptions.TimeoutError: 128 | msg = await jdbot.send_message(chat_id, '选择已超时,对话已停止') 129 | except Exception as e: 130 | await jdbot.send_message(chat_id, f'something wrong,I\'m sorry\n{str(e)}') 131 | logger.error(f'something wrong,I\'m sorry\n{str(e)}') 132 | -------------------------------------------------------------------------------- /jbot/bot/geturlfile.py: -------------------------------------------------------------------------------- 1 | from telethon import events, Button 2 | import requests 3 | from asyncio import exceptions 4 | from .. import jdbot, chat_id, logger, SCRIPTS_DIR, CONFIG_DIR, logger, BOT_SET, ch_name 5 | from .utils import press_event, backup_file, Remove_file, add_cron, cmd, DIY_DIR, TASK_CMD, split_list 6 | import json 7 | import os 8 | 9 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'^/dl')) 10 | async def bot_url_file(event): 11 | '''接收github链接后执行程序''' 12 | msg_text = event.raw_text.split(' ') 13 | try: 14 | if isinstance(msg_text,list) and len(msg_text) == 2: 15 | url = msg_text[-1] 16 | else: 17 | url = None 18 | SENDER = event.sender_id 19 | if not url: 20 | await jdbot.send_message(chat_id, '请正确使用dl命令,需加入下载链接') 21 | return 22 | else: 23 | msg = await jdbot.send_message(chat_id, '请稍后正在下载文件') 24 | 25 | if '下载代理' in BOT_SET.keys() and str(BOT_SET['下载代理']).lower() != 'false' and 'github' in url: 26 | url = f'{str(BOT_SET["下载代理"])}/{url}' 27 | 28 | filename = url.split('/')[-1] 29 | resp = requests.get(url).text 30 | 31 | btn = [] 32 | 33 | issetconfig=False 34 | 35 | if os.path.exists("/ql/data/config/auth.json"): 36 | configpath="/ql/data/" 37 | 38 | if os.path.exists("/ql/config/auth.json"): 39 | configpath="/ql/" 40 | 41 | if os.path.exists("/jd/config/config.sh"): 42 | configpath="/jd/" 43 | 44 | try: 45 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 46 | ccbotSetting = json.loads(f.read()) 47 | f.close() 48 | for key in ccbotSetting: 49 | if key=="文件存放配置": 50 | issetconfig=True 51 | except Exception as e: 52 | await jdbot.send_message(chat_id,f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 53 | return 54 | 55 | if not issetconfig: 56 | await jdbot.send_message(chat_id, f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 57 | return 58 | 59 | getfileSettinglist=ccbotSetting["文件存放配置"] 60 | 61 | countbtn=3 62 | for fileSetting in getfileSettinglist: 63 | if fileSetting["按钮名字"]=="配置档": 64 | countbtn=int(fileSetting["每行按钮数"]) 65 | else: 66 | btn.append(Button.inline(fileSetting["按钮名字"], data=fileSetting["按钮名字"]+"|"+fileSetting["存放路径"])) 67 | btn.append(Button.inline('取消', data='取消|cancel')) 68 | btn = split_list(btn, countbtn) 69 | 70 | 71 | if resp: 72 | markup = [] 73 | cmdtext = None 74 | runcmd = "" 75 | 76 | async with jdbot.conversation(SENDER, timeout=30) as conv: 77 | await jdbot.delete_messages(chat_id, msg) 78 | msg = await conv.send_message('请选择您要放入的文件夹或操作:\n') 79 | markup = btn 80 | msg = await jdbot.edit_message(msg, '请选择您要放入的文件夹或操作:', buttons=markup) 81 | convdata = await conv.wait_event(press_event(SENDER)) 82 | 83 | res = bytes.decode(convdata.data) 84 | isbackup="1" 85 | noaskaddcron="0" 86 | 87 | for fileSetting in getfileSettinglist: 88 | if fileSetting["按钮名字"]=="配置档": 89 | continue 90 | if fileSetting["按钮名字"]==res.split("|")[0]: 91 | isbackup=fileSetting["备份原脚本"] 92 | for key in fileSetting: 93 | if "执行命令" in key: 94 | if runcmd!="" : 95 | runcmd=runcmd+"\n" 96 | runcmd=runcmd+fileSetting[key].replace("文件名",filename) 97 | if "不问是否定时" in key: 98 | noaskaddcron=fileSetting[key] 99 | isrun="0" 100 | res=res.split("|")[1] 101 | if "task " in res: 102 | isrun="1" 103 | res=res.replace("task ","") 104 | 105 | markup = [Button.inline('是', data='yes'), 106 | Button.inline('否', data='no')] 107 | if res == 'cancel': 108 | msg = await jdbot.edit_message(msg, '对话已取消') 109 | conv.cancel() 110 | else: 111 | res2="" 112 | if noaskaddcron=="0": 113 | msg = await jdbot.edit_message(msg, '是否尝试自动加入定时', buttons=markup) 114 | convdata2 = await conv.wait_event(press_event(SENDER)) 115 | res2 = bytes.decode(convdata2.data) 116 | 117 | if isbackup=="1": 118 | backup_file(f'{res}/{filename}') 119 | else: 120 | Remove_file(f'{res}/{filename}') 121 | 122 | if isrun=="1": 123 | cmdtext = f'{TASK_CMD} {res}/{filename} now' 124 | 125 | with open(f'{res}/{filename}', 'w+', encoding='utf-8') as f: 126 | f.write(resp) 127 | 128 | if res2 == 'yes': 129 | await add_cron(jdbot, conv, resp, filename, msg, SENDER, markup, res) 130 | else: 131 | await jdbot.edit_message(msg, f'{filename}已保存到{res}文件夹') 132 | conv.cancel() 133 | if cmdtext: 134 | if runcmd!="": 135 | runcmd=cmdtext+"\n"+runcmd 136 | else: 137 | runcmd=cmdtext 138 | 139 | if runcmd!="": 140 | msg=await jdbot.send_message(chat_id,"开始执行命令列表"+":\n"+runcmd) 141 | cmdlist=runcmd.split("\n") 142 | for RunCommound in cmdlist: 143 | await cmd(RunCommound) 144 | 145 | await jdbot.edit_message(msg, '任务执行完毕,祝君愉快.') 146 | 147 | except exceptions.TimeoutError: 148 | msg = await jdbot.send_message(chat_id, '选择已超时,对话已停止') 149 | except Exception as e: 150 | await jdbot.send_message(chat_id, f'something wrong,I\'m sorry\n{str(e)}') 151 | logger.error(f'something wrong,I\'m sorry\n{str(e)}') 152 | 153 | if ch_name: 154 | jdbot.add_event_handler(bot_url_file, events.NewMessage( 155 | from_users=chat_id, pattern=BOT_SET['命令别名']['dl'])) 156 | -------------------------------------------------------------------------------- /jbot/bot/utils.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | from functools import wraps 4 | from telethon import events, Button 5 | import re 6 | import time 7 | import json 8 | from .. import jdbot, chat_id, LOG_DIR, logger, JD_DIR, OWN_DIR, CONFIG_DIR, BOT_SET 9 | import asyncio 10 | import datetime 11 | import random 12 | row = int(BOT_SET['每页列数']) 13 | CRON_FILE = f'{CONFIG_DIR}/crontab.list' 14 | BEAN_LOG_DIR = f'{LOG_DIR}/jd_bean_change/' 15 | CONFIG_SH_FILE = f'{CONFIG_DIR}/config.sh' 16 | V4, QL = False, False 17 | if os.environ.get('JD_DIR'): 18 | V4 = True 19 | AUTH_FILE = None 20 | if os.path.exists(f'{CONFIG_DIR}/cookie.sh'): 21 | CONFIG_SH_FILE = f'{CONFIG_DIR}/cookie.sh' 22 | DIY_DIR = OWN_DIR 23 | TASK_CMD = 'jtask' 24 | elif os.environ.get('QL_DIR'): 25 | QL = True 26 | AUTH_FILE = f'{CONFIG_DIR}/auth.json' 27 | DIY_DIR = None 28 | TASK_CMD = 'task' 29 | dirs = os.listdir(LOG_DIR) 30 | for mydir in dirs: 31 | if 'jd_bean_change' in mydir: 32 | BEAN_LOG_DIR = f'{LOG_DIR}/{mydir}' 33 | break 34 | else: 35 | DIY_DIR = None 36 | TASK_CMD = 'node' 37 | 38 | 39 | def Ver_Main(func): 40 | @wraps(func) 41 | def wrapper(*args, **kwargs): 42 | res = func(*args, **kwargs) 43 | if str(res).find('valid sign') > -1 : 44 | msg = ql_login() 45 | return {'code': 400, 'data': msg} 46 | return res 47 | return wrapper 48 | 49 | 50 | def ql_login(): 51 | url = 'http://127.0.0.1:5600/api/login' 52 | with open(AUTH_FILE, 'r', encoding='utf-8') as f: 53 | auth = json.load(f) 54 | data = {'username': auth['username'], 'password': auth['password']} 55 | try: 56 | res = requests.post(url, json=data).json() 57 | if res['code'] == 200: 58 | return '自动登录成功,请重新执行命令' 59 | elif res['message'].find('两步验证') > -1: 60 | return ' 当前登录已过期,且已开启两步登录验证,请使用命令/auth 六位验证码完成登录' 61 | except Exception as e: 62 | return '自动登录出错:' + str(e) 63 | 64 | 65 | def get_cks(ckfile): 66 | ck_reg = re.compile(r'pt_key=\S*?;.*?pt_pin=\S*?;') 67 | cookie_file = r'/ql/db/cookie.db' 68 | if QL and not os.path.exists(cookie_file): 69 | with open(ckfile, 'r', encoding='utf-8') as f: 70 | auth = json.load(f) 71 | lines = str(env_manage_QL('search', 'JD_COOKIE', auth['token'])) 72 | elif QL: 73 | with open(f'{CONFIG_DIR}/cookie.sh', 'r', encoding='utf-8') as f: 74 | lines = f.read() 75 | else: 76 | with open(ckfile, 'r', encoding='utf-8') as f: 77 | lines = f.read() 78 | cookies = ck_reg.findall(lines) 79 | for ck in cookies: 80 | if ck == 'pt_key=xxxxxxxxxx;pt_pin=xxxx;': 81 | cookies.remove(ck) 82 | break 83 | return cookies 84 | 85 | 86 | def split_list(datas, n, row: bool = True): 87 | """一维列表转二维列表,根据N不同,生成不同级别的列表""" 88 | length = len(datas) 89 | size = length / n + 1 if length % n else length/n 90 | _datas = [] 91 | if not row: 92 | size, n = n, size 93 | for i in range(int(size)): 94 | start = int(i * n) 95 | end = int((i + 1) * n) 96 | _datas.append(datas[start:end]) 97 | return _datas 98 | 99 | 100 | def backup_file(file): 101 | '''如果文件存在,则备份,并更新''' 102 | if os.path.exists(file): 103 | try: 104 | os.rename(file, f'{file}.bak') 105 | except WindowsError: 106 | os.remove(f'{file}.bak') 107 | os.rename(file, f'{file}.bak') 108 | 109 | def Remove_file(file): 110 | '''如果文件存在,则删除,并更新''' 111 | if os.path.exists(file): 112 | try: 113 | os.remove(file) 114 | except WindowsError: 115 | os.remove(f'{file}.bak') 116 | os.rename(file, f'{file}.bak') 117 | 118 | def press_event(user_id): 119 | return events.CallbackQuery(func=lambda e: e.sender_id == user_id) 120 | 121 | 122 | async def cmd(cmdtext): 123 | '''定义执行cmd命令''' 124 | try: 125 | msg = await jdbot.send_message(chat_id, '开始执行命令') 126 | p = await asyncio.create_subprocess_shell( 127 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 128 | res_bytes, res_err = await p.communicate() 129 | res = res_bytes.decode('utf-8') 130 | if res.find('先登录') > -1: 131 | await jdbot.delete_messages(chat_id, msg) 132 | res, msg = ql_login() 133 | await jdbot.send_message(chat_id, msg) 134 | return 135 | if len(res) == 0: 136 | await jdbot.edit_message(msg, '已执行,但返回值为空') 137 | elif len(res) <= 4000: 138 | await jdbot.delete_messages(chat_id, msg) 139 | res=msgformat(res) 140 | await jdbot.send_message(chat_id, res) 141 | elif len(res) > 4000: 142 | tmp_log = f'{LOG_DIR}/bot/{cmdtext.split("/")[-1].split(".js")[0]}-{datetime.datetime.now().strftime("%H-%M-%S")}_{random.randint(1,99)}.log' 143 | with open(tmp_log, 'w+', encoding='utf-8') as f: 144 | f.write(res) 145 | await jdbot.delete_messages(chat_id, msg) 146 | await jdbot.send_message(chat_id, '执行结果较长,请查看日志', file=tmp_log) 147 | os.remove(tmp_log) 148 | except Exception as e: 149 | await jdbot.send_message(chat_id, f'something wrong,I\'m sorry\n{str(e)}') 150 | logger.error(f'something wrong,I\'m sorry\n{str(e)}') 151 | 152 | def msgformat(text): 153 | replaceArr = ['_', '*', '~'] 154 | for i in replaceArr: 155 | t = '' 156 | for a in range(5): 157 | t += i 158 | text = re.sub('\%s{6,}' % i, t, text) 159 | return text 160 | 161 | def get_ch_names(path, dir): 162 | '''获取文件中文名称,如无则返回文件名''' 163 | file_ch_names = [] 164 | reg = r'new Env\(\'[\S]+?\'\)' 165 | ch_name = False 166 | for file in dir: 167 | try: 168 | if os.path.isdir(f'{path}/{file}'): 169 | file_ch_names.append(file) 170 | elif file.endswith('.js') and file != 'jdCookie.js' and file != 'getJDCookie.js' and file != 'JD_extra_cookie.js' and 'ShareCode' not in file: 171 | with open(f'{path}/{file}', 'r', encoding='utf-8') as f: 172 | lines = f.readlines() 173 | for line in lines: 174 | if 'new Env' in line: 175 | line = line.replace('\"', '\'') 176 | res = re.findall(reg, line) 177 | if len(res) != 0: 178 | res = res[0].split('\'')[-2] 179 | file_ch_names.append(f'{res}--->{file}') 180 | ch_name = True 181 | break 182 | if not ch_name: 183 | file_ch_names.append(f'{file}--->{file}') 184 | ch_name = False 185 | else: 186 | continue 187 | except: 188 | continue 189 | return file_ch_names 190 | 191 | 192 | async def log_btn(conv, sender, path, msg, page, files_list): 193 | '''定义log日志按钮''' 194 | my_btns = [Button.inline('上一页', data='up'), Button.inline( 195 | '下一页', data='next'), Button.inline('上级', data='updir'), Button.inline('取消', data='cancel')] 196 | try: 197 | if files_list: 198 | markup = files_list 199 | new_markup = markup[page] 200 | if my_btns not in new_markup: 201 | new_markup.append(my_btns) 202 | else: 203 | dir = os.listdir(path) 204 | dir.sort() 205 | if path == LOG_DIR: 206 | markup = [Button.inline("_".join(file.split("_")[-2:]), data=str(file)) 207 | for file in dir] 208 | elif os.path.dirname(os.path.realpath(path)) == LOG_DIR: 209 | markup = [Button.inline("-".join(file.split("-")[-5:]), data=str(file)) 210 | for file in dir] 211 | else: 212 | markup = [Button.inline(file, data=str(file)) 213 | for file in dir] 214 | markup = split_list(markup, row) 215 | if len(markup) > 30: 216 | markup = split_list(markup, 30) 217 | new_markup = markup[page] 218 | new_markup.append(my_btns) 219 | else: 220 | new_markup = markup 221 | if path == JD_DIR: 222 | new_markup.append([Button.inline('取消', data='cancel')]) 223 | else: 224 | new_markup.append( 225 | [Button.inline('上级', data='updir'), Button.inline('取消', data='cancel')]) 226 | msg = await jdbot.edit_message(msg, '请做出您的选择:', buttons=new_markup) 227 | convdata = await conv.wait_event(press_event(sender)) 228 | res = bytes.decode(convdata.data) 229 | if res == 'cancel': 230 | msg = await jdbot.edit_message(msg, '对话已取消') 231 | conv.cancel() 232 | return None, None, None, None 233 | elif res == 'next': 234 | page = page + 1 235 | if page > len(markup) - 1: 236 | page = 0 237 | return path, msg, page, markup 238 | elif res == 'up': 239 | page = page - 1 240 | if page < 0: 241 | page = len(markup) - 1 242 | return path, msg, page, markup 243 | elif res == 'updir': 244 | path = '/'.join(path.split('/')[:-1]) 245 | if path == '': 246 | path = JD_DIR 247 | return path, msg, page, None 248 | elif os.path.isfile(f'{path}/{res}'): 249 | msg = await jdbot.edit_message(msg, '文件发送中,请注意查收') 250 | await conv.send_file(f'{path}/{res}') 251 | msg = await jdbot.edit_message(msg, f'{res}发送成功,请查收') 252 | conv.cancel() 253 | return None, None, None, None 254 | else: 255 | return f'{path}/{res}', msg, page, None 256 | except asyncio.exceptions.TimeoutError: 257 | msg = await jdbot.edit_message(msg, '选择已超时,本次对话已停止') 258 | return None, None, None, None 259 | except Exception as e: 260 | msg = await jdbot.edit_message(msg, f'something wrong,I\'m sorry\n{str(e)}') 261 | logger.error(f'something wrong,I\'m sorry\n{str(e)}') 262 | return None, None, None, None 263 | 264 | 265 | async def snode_btn(conv, sender, path, msg, page, files_list): 266 | '''定义scripts脚本按钮''' 267 | my_btns = [Button.inline('上一页', data='up'), Button.inline( 268 | '下一页', data='next'), Button.inline('上级', data='updir'), Button.inline('取消', data='cancel')] 269 | try: 270 | if files_list: 271 | markup = files_list 272 | new_markup = markup[page] 273 | if my_btns not in new_markup: 274 | new_markup.append(my_btns) 275 | else: 276 | if path == JD_DIR and V4: 277 | dir = ['scripts', OWN_DIR.split('/')[-1]] 278 | elif path == JD_DIR and QL: 279 | dir = ['scripts'] 280 | else: 281 | dir = os.listdir(path) 282 | if BOT_SET['中文'].lower() == "true": 283 | dir = get_ch_names(path, dir) 284 | dir.sort() 285 | markup = [Button.inline(file.split('--->')[0], data=str(file.split('--->')[-1])) 286 | for file in dir if os.path.isdir(f'{path}/{file}') or file.endswith('.js')] 287 | markup = split_list(markup, row) 288 | if len(markup) > 30: 289 | markup = split_list(markup, 30) 290 | new_markup = markup[page] 291 | new_markup.append(my_btns) 292 | else: 293 | new_markup = markup 294 | if path == JD_DIR: 295 | new_markup.append([Button.inline('取消', data='cancel')]) 296 | else: 297 | new_markup.append( 298 | [Button.inline('上级', data='updir'), Button.inline('取消', data='cancel')]) 299 | msg = await jdbot.edit_message(msg, '请做出您的选择:', buttons=new_markup) 300 | convdata = await conv.wait_event(press_event(sender)) 301 | res = bytes.decode(convdata.data) 302 | if res == 'cancel': 303 | msg = await jdbot.edit_message(msg, '对话已取消') 304 | conv.cancel() 305 | return None, None, None, None 306 | elif res == 'next': 307 | page = page + 1 308 | if page > len(markup) - 1: 309 | page = 0 310 | return path, msg, page, markup 311 | elif res == 'up': 312 | page = page - 1 313 | if page < 0: 314 | page = len(markup) - 1 315 | return path, msg, page, markup 316 | elif res == 'updir': 317 | path = '/'.join(path.split('/')[:-1]) 318 | if path == '': 319 | path = JD_DIR 320 | return path, msg, page, None 321 | elif os.path.isfile(f'{path}/{res}'): 322 | conv.cancel() 323 | logger.info(f'{path}/{res} 脚本即将在后台运行') 324 | msg = await jdbot.edit_message(msg, f'{res} 在后台运行成功') 325 | cmdtext = f'{TASK_CMD} {path}/{res} now' 326 | return None, None, None, f'CMD-->{cmdtext}' 327 | else: 328 | return f'{path}/{res}', msg, page, None 329 | except asyncio.exceptions.TimeoutError: 330 | msg = await jdbot.edit_message(msg, '选择已超时,对话已停止') 331 | return None, None, None, None 332 | except Exception as e: 333 | msg = await jdbot.edit_message(msg, f'something wrong,I\'m sorry\n{str(e)}') 334 | logger.error(f'something wrong,I\'m sorry\n{str(e)}') 335 | return None, None, None, None 336 | 337 | 338 | def mycron(lines): 339 | cronreg = re.compile(r'([0-9\-\*/,]{1,} ){4,5}([0-9\-\*/,]){1,}') 340 | return cronreg.search(lines).group() 341 | 342 | def add_cron_V4(cron): 343 | owninfo = '# mtask任务区域' 344 | with open(CRON_FILE, 'r', encoding='utf-8') as f: 345 | lines = f.readlines() 346 | for line in lines: 347 | if owninfo in line: 348 | i = lines.index(line) 349 | lines.insert(i+1, cron+'\n') 350 | break 351 | with open(CRON_FILE, 'w', encoding='utf-8') as f: 352 | f.write(''.join(lines)) 353 | 354 | 355 | async def add_cron(jdbot, conv, resp, filename, msg, sender, markup, path): 356 | try: 357 | if QL: 358 | crondata = { 359 | "name": f'{filename.split(".")[0]}', "command": f'task {path}/{filename}', "schedule": f'{mycron(resp)}'} 360 | else: 361 | crondata = f'{mycron(resp)} mtask {path}/{filename}' 362 | msg = await jdbot.edit_message(msg, f'已识别定时\n```{crondata}```\n是否需要修改', buttons=markup) 363 | except: 364 | if QL: 365 | crondata = { 366 | "name": f'{filename.split(".")[0]}', "command": f'task {path}/{filename}', "schedule": f'0 0 * * *'} 367 | else: 368 | crondata = f'0 0 * * * mtask {path}/{filename}' 369 | msg = await jdbot.edit_message(msg, f'未识别到定时,默认定时\n```{crondata}```\n是否需要修改', buttons=markup) 370 | convdata3 = await conv.wait_event(press_event(sender)) 371 | res3 = bytes.decode(convdata3.data) 372 | if res3 == 'yes': 373 | convmsg = await conv.send_message(f'```{crondata}```\n请输入您要修改内容,可以直接点击上方定时进行复制修改\n如果需要取消,请输入`cancel`或`取消`') 374 | crondata = await conv.get_response() 375 | crondata = crondata.raw_text 376 | if crondata == 'cancel' or crondata == '取消': 377 | conv.cancel() 378 | await jdbot.send_message(chat_id, '对话已取消') 379 | return 380 | await jdbot.delete_messages(chat_id, convmsg) 381 | await jdbot.delete_messages(chat_id, msg) 382 | if QL: 383 | with open(AUTH_FILE, 'r', encoding='utf-8') as f: 384 | auth = json.load(f) 385 | res = cron_manage_QL('add', json.loads( 386 | str(crondata).replace('\'', '\"')), auth['token']) 387 | if res['code'] == 200: 388 | await jdbot.send_message(chat_id, f'{filename}已保存到{path},并已尝试添加定时任务') 389 | else: 390 | await jdbot.send_message(chat_id, f'{filename}已保存到{path},定时任务添加失败,{res["data"]}') 391 | else: 392 | add_cron_V4(crondata) 393 | await jdbot.send_message(chat_id, f'{filename}已保存到{path},并已尝试添加定时任务') 394 | 395 | 396 | @Ver_Main 397 | def cron_manage_QL(fun, crondata, token): 398 | url = 'http://127.0.0.1:5600/api/crons' 399 | headers = { 400 | 'Authorization': f'Bearer {token}' 401 | } 402 | try: 403 | if fun == 'search': 404 | params = { 405 | 't': int(round(time.time() * 1000)), 406 | 'searchValue': crondata 407 | } 408 | res = requests.get(url, params=params, headers=headers).json() 409 | elif fun == 'add': 410 | data = { 411 | 'name': crondata['name'], 412 | 'command': crondata['command'], 413 | 'schedule': crondata['schedule'] 414 | } 415 | res = requests.post(url, data=data, headers=headers).json() 416 | elif fun == 'run': 417 | data = [crondata['id']] 418 | res = requests.put(f'{url}/run', json=data, headers=headers).json() 419 | elif fun == 'log': 420 | data = crondata['id'] 421 | res = requests.get(f'{url}/{data}/log', headers=headers).json() 422 | elif fun == 'edit': 423 | data = { 424 | 'name': crondata['name'], 425 | 'command': crondata['command'], 426 | 'schedule': crondata['schedule'], 427 | 'id': crondata['id'] 428 | } 429 | res = requests.put(url, json=data, headers=headers).json() 430 | elif fun == 'disable': 431 | data = [crondata['id']] 432 | res = requests.put(url+'/disable', json=data, 433 | headers=headers).json() 434 | elif fun == 'enable': 435 | data = [crondata['id']] 436 | res = requests.put(url+'/enable', json=data, 437 | headers=headers).json() 438 | elif fun == 'del': 439 | data = [crondata['id']] 440 | res = requests.delete(url, json=data, headers=headers).json() 441 | else: 442 | res = {'code': 400, 'data': '未知功能'} 443 | except Exception as e: 444 | res = {'code': 400, 'data': str(e)} 445 | finally: 446 | return res 447 | 448 | 449 | def cron_manage_V4(fun, crondata): 450 | file = f'{CONFIG_DIR}/crontab.list' 451 | with open(file, 'r', encoding='utf-8') as f: 452 | v4crons = f.readlines() 453 | try: 454 | if fun == 'search': 455 | res = {'code': 200, 'data': {}} 456 | for cron in v4crons: 457 | if str(crondata) in cron: 458 | res['data'][cron.split( 459 | 'task ')[-1].split(' ')[0].split('/')[-1].replace('\n', '')] = cron 460 | elif fun == 'add': 461 | v4crons.append(crondata) 462 | res = {'code': 200, 'data': 'success'} 463 | elif fun == 'run': 464 | cmd(f'jtask {crondata.split("task")[-1]}') 465 | res = {'code': 200, 'data': 'success'} 466 | elif fun == 'edit': 467 | ocron, ncron = crondata.split('-->') 468 | i = v4crons.index(ocron) 469 | v4crons.pop(i) 470 | v4crons.insert(i, ncron) 471 | res = {'code': 200, 'data': 'success'} 472 | elif fun == 'disable': 473 | i = v4crons.index(crondata) 474 | crondatal = list(crondata) 475 | crondatal.insert(0, '#') 476 | ncron = ''.join(crondatal) 477 | v4crons.pop(i) 478 | v4crons.insert(i, ncron) 479 | res = {'code': 200, 'data': 'success'} 480 | elif fun == 'enable': 481 | i = v4crons.index(crondata) 482 | ncron = crondata.replace('#', '') 483 | v4crons.pop(i) 484 | v4crons.insert(i, ncron) 485 | res = {'code': 200, 'data': 'success'} 486 | elif fun == 'del': 487 | i = v4crons.index(crondata) 488 | v4crons.pop(i) 489 | res = {'code': 200, 'data': 'success'} 490 | else: 491 | res = {'code': 400, 'data': '未知功能'} 492 | with open(file, 'w', encoding='utf-8') as f: 493 | f.write(''.join(v4crons)) 494 | except Exception as e: 495 | res = {'code': 400, 'data': str(e)} 496 | finally: 497 | return res 498 | 499 | 500 | def cron_manage(fun, crondata, token): 501 | if QL: 502 | res = cron_manage_QL(fun, crondata, token) 503 | else: 504 | res = cron_manage_V4(fun, crondata) 505 | return res 506 | 507 | 508 | @Ver_Main 509 | def env_manage_QL(fun, envdata, token): 510 | url = 'http://127.0.0.1:5600/api/envs' 511 | headers = { 512 | 'Authorization': f'Bearer {token}' 513 | } 514 | try: 515 | if fun == 'search': 516 | params = { 517 | 't': int(round(time.time() * 1000)), 518 | 'searchValue': envdata 519 | } 520 | res = requests.get(url, params=params, headers=headers).json() 521 | elif fun == 'add': 522 | data = { 523 | 'name': envdata['name'], 524 | 'value': envdata['value'], 525 | 'remarks': envdata['remarks'] if 'remarks' in envdata.keys() else '' 526 | } 527 | res = requests.post(url, json=[data], headers=headers).json() 528 | elif fun == 'edit': 529 | data = { 530 | 'name': envdata['name'], 531 | 'value': envdata['value'], 532 | 'id': envdata['id'], 533 | 'remarks': envdata['remarks'] if 'remarks' in envdata.keys() else '' 534 | } 535 | res = requests.put(url, json=data, headers=headers).json() 536 | elif fun == 'disable': 537 | data = [envdata['id']] 538 | res = requests.put(url+'/disable', json=data, 539 | headers=headers).json() 540 | elif fun == 'enable': 541 | data = [envdata['id']] 542 | res = requests.put(url+'/enable', json=data, 543 | headers=headers).json() 544 | elif fun == 'del': 545 | data = [envdata['id']] 546 | res = requests.delete(url, json=data, headers=headers).json() 547 | else: 548 | res = {'code': 400, 'data': '未知功能'} 549 | except Exception as e: 550 | res = {'code': 400, 'data': str(e)} 551 | finally: 552 | return res 553 | -------------------------------------------------------------------------------- /jbot/diy/CheckCK.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import os 6 | import sys 7 | import re 8 | from telethon import events, Button 9 | 10 | from .. import chat_id, jdbot, logger, ch_name, BOT_SET 11 | from ..bot.utils import cmd, TASK_CMD,split_list, press_event 12 | from .utils import read, write 13 | import asyncio 14 | 15 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'^/cck')) 16 | async def CheckCK(event): 17 | try: 18 | await event.edit('开始检查账号情况,请稍后...') 19 | 20 | cmdtext="task /ql/repo/ccwav_QLScript2/bot_jd_CkSeq.js now" 21 | p = await asyncio.create_subprocess_shell( 22 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 23 | res_bytes, res_err = await p.communicate() 24 | res = res_bytes.decode('utf-8') 25 | txt=res.split('\n') 26 | strReturn="" 27 | intcount=0 28 | if res: 29 | await event.delete() 30 | for line in txt: 31 | if "分割行" in line: 32 | intcount=0 33 | if strReturn: 34 | await jdbot.send_message(chat_id, strReturn) 35 | strReturn="" 36 | else: 37 | if "】" in line or "没有出现" in line or "今日正常" in line : 38 | strReturn=strReturn+line+'\n' 39 | intcount=intcount+1 40 | if intcount==70: 41 | intcount=0 42 | if strReturn: 43 | await jdbot.send_message(chat_id, strReturn) 44 | strReturn="" 45 | else: 46 | await jdbot.send_message(chat_id, "查询失败!") 47 | 48 | if strReturn: 49 | await jdbot.send_message(chat_id, strReturn) 50 | 51 | except Exception as e: 52 | title = "【💥错误💥】" 53 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 54 | function = "函数名:" + sys._getframe().f_code.co_name 55 | tip = '建议百度/谷歌进行查询' 56 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n\n{tip}") 57 | logger.error(f"错误--->{str(e)}") 58 | 59 | 60 | if ch_name: 61 | jdbot.add_event_handler(CheckCK, events.NewMessage(from_users=chat_id, pattern=BOT_SET['命令别名']['cron'])) 62 | 63 | -------------------------------------------------------------------------------- /jbot/diy/Router.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import os 6 | import sys 7 | 8 | from telethon import events 9 | 10 | from .. import chat_id, jdbot, logger, ch_name, BOT_SET 11 | from ..bot.utils import cmd, TASK_CMD 12 | import asyncio 13 | import time 14 | import json 15 | 16 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'^/routerinfo$')) 17 | async def RouterInfo(event): 18 | try: 19 | #载入设定 20 | scriptpath="" 21 | issetconfig=False 22 | if os.path.exists("/ql/data/config/auth.json"): 23 | configpath="/ql/data/" 24 | 25 | if os.path.exists("/ql/config/auth.json"): 26 | configpath="/ql/" 27 | 28 | if os.path.exists("/jd/config/config.sh"): 29 | configpath="/jd/" 30 | 31 | try: 32 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 33 | ccbotSetting = json.loads(f.read()) 34 | f.close() 35 | for key in ccbotSetting: 36 | if key=="路由器命令配置": 37 | issetconfig=True 38 | except Exception as e: 39 | await event.edit(f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 40 | return 41 | 42 | if not issetconfig: 43 | await event.edit(f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 44 | return 45 | 46 | try: 47 | for key in ccbotSetting["路由器命令配置"]: 48 | if key=="查询信息脚本文件地址": 49 | scriptpath=ccbotSetting["路由器命令配置"][key] 50 | 51 | except Exception as e: 52 | await event.edit(f'载入ccbotSetting.json的cb命令配置内容出错,请检查!\n'+str(e)) 53 | return 54 | 55 | if scriptpath=="": 56 | await event.edit(f'ccbotSetting.json中的cb命令配置没有填写查询信息脚本文件地址,请检查!') 57 | return 58 | 59 | if not os.path.exists(scriptpath): 60 | await event.edit(f'ccbotSetting.json中的cb命令配置的查询信息脚本文件不存在,请检查!\n'+scriptpath) 61 | return 62 | 63 | 64 | cmdtext="task "+scriptpath+" now" 65 | p = await asyncio.create_subprocess_shell( 66 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 67 | res_bytes, res_err = await p.communicate() 68 | res = res_bytes.decode('utf-8') 69 | txt=res.split('\n') 70 | strReturn="" 71 | if res: 72 | for line in txt: 73 | if "名称" in line or "地址" in line or "内存" in line : 74 | strReturn=strReturn+line+'\n' 75 | 76 | if strReturn: 77 | await jdbot.send_message(chat_id, strReturn) 78 | else: 79 | await jdbot.send_message(chat_id,'未能获取路由器信息!') 80 | 81 | except Exception as e: 82 | title = "【💥错误💥】" 83 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 84 | function = "函数名:" + sys._getframe().f_code.co_name 85 | tip = '建议百度/谷歌进行查询' 86 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n\n{tip}") 87 | logger.error(f"错误--->{str(e)}") 88 | 89 | 90 | if ch_name: 91 | jdbot.add_event_handler(RouterInfo, events.NewMessage(from_users=chat_id, pattern=BOT_SET['命令别名']['cron'])) 92 | 93 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'^/routerip$')) 94 | async def RouterResetIP(event): 95 | try: 96 | #载入设定 97 | scriptpath1="" 98 | scriptpath2="" 99 | issetconfig=False 100 | if os.path.exists("/ql/data/config/auth.json"): 101 | configpath="/ql/data/" 102 | 103 | if os.path.exists("/ql/config/auth.json"): 104 | configpath="/ql/" 105 | 106 | if os.path.exists("/jd/config/config.sh"): 107 | configpath="/jd/" 108 | 109 | try: 110 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 111 | ccbotSetting = json.loads(f.read()) 112 | f.close() 113 | for key in ccbotSetting: 114 | if key=="路由器命令配置": 115 | issetconfig=True 116 | except Exception as e: 117 | await event.edit(f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 118 | return 119 | 120 | if not issetconfig: 121 | await event.edit(f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 122 | return 123 | 124 | try: 125 | for key in ccbotSetting["路由器命令配置"]: 126 | if key=="查询信息脚本文件地址": 127 | scriptpath1=ccbotSetting["路由器命令配置"][key] 128 | if key=="重拨路由脚本文件地址": 129 | scriptpath2=ccbotSetting["路由器命令配置"][key] 130 | 131 | except Exception as e: 132 | await event.edit(f'载入ccbotSetting.json的cb命令配置内容出错,请检查!\n'+str(e)) 133 | return 134 | 135 | if scriptpath1=="": 136 | await event.edit(f'ccbotSetting.json中的cb命令配置没有填写查询信息脚本文件地址,请检查!') 137 | return 138 | 139 | if not os.path.exists(scriptpath1): 140 | await event.edit(f'ccbotSetting.json中的cb命令配置的查询信息脚本文件不存在,请检查!\n'+scriptpath1) 141 | return 142 | 143 | if scriptpath2=="": 144 | await event.edit(f'ccbotSetting.json中的cb命令配置没有填写重拨路由脚本文件地址,请检查!') 145 | return 146 | 147 | if not os.path.exists(scriptpath2): 148 | await event.edit(f'ccbotSetting.json中的cb命令配置的重拨路由脚本文件不存在,请检查!\n'+scriptpath1) 149 | return 150 | 151 | cmdtext="task "+scriptpath1+" now" 152 | p = await asyncio.create_subprocess_shell( 153 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 154 | res_bytes, res_err = await p.communicate() 155 | res = res_bytes.decode('utf-8') 156 | txt=res.split('\n') 157 | strReturn="" 158 | if res: 159 | for line in txt: 160 | if "名称" in line or "地址" in line : 161 | strReturn=strReturn+line+'\n' 162 | 163 | if strReturn: 164 | await jdbot.send_message(chat_id, strReturn+"开始通知路由器重新拨号,请断网重连后自行查看IP是否变更,祝您生活愉快....") 165 | await asyncio.sleep(5) 166 | else: 167 | await jdbot.send_message(chat_id,'未能获取路由器信息!') 168 | return 169 | 170 | cmdtext="task "+scriptpath2+" now" 171 | p = await asyncio.create_subprocess_shell( 172 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 173 | res_bytes, res_err = await p.communicate() 174 | res = res_bytes.decode('utf-8') 175 | txt=res.split('\n') 176 | strReturn="" 177 | if res: 178 | for line in txt: 179 | if "结果" in line : 180 | strReturn=strReturn+line+'\n' 181 | if strReturn: 182 | await asyncio.sleep(20) 183 | await jdbot.send_message(chat_id, strReturn) 184 | else: 185 | await jdbot.send_message(chat_id,'路由器没有返回信息,重拨失败!') 186 | 187 | except Exception as e: 188 | title = "【💥错误💥】" 189 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 190 | function = "函数名:" + sys._getframe().f_code.co_name 191 | tip = '建议百度/谷歌进行查询' 192 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n\n{tip}") 193 | logger.error(f"错误--->{str(e)}") 194 | 195 | 196 | if ch_name: 197 | jdbot.add_event_handler(RouterResetIP, events.NewMessage(from_users=chat_id, pattern=BOT_SET['命令别名']['cron'])) 198 | -------------------------------------------------------------------------------- /jbot/diy/ccbean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import os 6 | import sys 7 | import re 8 | from telethon import events, Button 9 | 10 | from .. import chat_id, jdbot, logger, ch_name, BOT_SET 11 | from ..bot.utils import cmd, TASK_CMD,split_list, press_event 12 | from .utils import read, write 13 | import asyncio 14 | import json 15 | 16 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'^/ccbean')) 17 | async def CCBeanInfo(event): 18 | try: 19 | msg_text = event.raw_text.split(' ') 20 | 21 | msg = await jdbot.send_message(chat_id, '正在查询,请稍后') 22 | if isinstance(msg_text, list) and len(msg_text) == 2: 23 | text = msg_text[-1] 24 | else: 25 | text = None 26 | 27 | if text==None: 28 | SENDER = event.sender_id 29 | btn = [] 30 | for i in range(11): 31 | btn.append(Button.inline(str(i+1), data=str(i+1))) 32 | btn.append(Button.inline('取消', data='cancel')) 33 | btn = split_list(btn, 3) 34 | async with jdbot.conversation(SENDER, timeout=90) as conv: 35 | info='请选择要查询的账号:' 36 | msg = await jdbot.edit_message(msg, info, buttons=btn, link_preview=False) 37 | convdata = await conv.wait_event(press_event(SENDER)) 38 | res = bytes.decode(convdata.data) 39 | if res == 'cancel': 40 | msg = await jdbot.edit_message(msg, '对话已取消') 41 | conv.cancel() 42 | else: 43 | text = res 44 | msg = await jdbot.edit_message(msg, '开始查询账号'+text+'的资产,请稍后...') 45 | 46 | if text==None: 47 | await jdbot.delete_messages(chat_id, msg) 48 | return 49 | 50 | #载入设定 51 | scriptpath="" 52 | issetconfig=False 53 | nocheck="" 54 | if os.path.exists("/ql/data/config/auth.json"): 55 | configpath="/ql/data/" 56 | 57 | if os.path.exists("/ql/config/auth.json"): 58 | configpath="/ql/" 59 | 60 | if os.path.exists("/jd/config/config.sh"): 61 | configpath="/jd/" 62 | 63 | try: 64 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 65 | ccbotSetting = json.loads(f.read()) 66 | f.close() 67 | for key in ccbotSetting: 68 | if key=="cb命令配置": 69 | issetconfig=True 70 | except Exception as e: 71 | await event.edit(f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 72 | return 73 | 74 | if not issetconfig: 75 | await event.edit(f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 76 | return 77 | 78 | try: 79 | for key in ccbotSetting["cb命令配置"]: 80 | if key=="脚本文件地址": 81 | scriptpath=ccbotSetting["cb命令配置"][key] 82 | if key=="关闭查询项目": 83 | nocheck=ccbotSetting["cb命令配置"][key] 84 | except Exception as e: 85 | await event.edit(f'载入ccbotSetting.json的cb命令配置内容出错,请检查!\n'+str(e)) 86 | return 87 | 88 | if scriptpath=="": 89 | await event.edit(f'ccbotSetting.json中的cb命令配置没有填写脚本文件地址,请检查!') 90 | return 91 | 92 | if not os.path.exists(scriptpath): 93 | await event.edit(f'ccbotSetting.json中的cb命令配置的脚本文件不存在,请检查!\n'+scriptpath) 94 | return 95 | 96 | key="BOTCHECKCODE" 97 | kv=f'{key}="{text}"' 98 | configs = read("str") 99 | if kv not in configs: 100 | if key in configs: 101 | configs = re.sub(f'{key}=("|\').*("|\')', kv, configs) 102 | write(configs) 103 | else: 104 | configs = read("str") 105 | configs += f'\nexport {key}="{text}"\n' 106 | write(configs) 107 | 108 | key="BEANCHANGE_BOTDISABLELIST" 109 | kv=f'{key}="{nocheck}"' 110 | configs = read("str") 111 | if kv not in configs: 112 | if key in configs: 113 | configs = re.sub(f'{key}=("|\').*("|\')', kv, configs) 114 | write(configs) 115 | else: 116 | configs = read("str") 117 | configs += f'\nexport {key}="{nocheck}"\n' 118 | write(configs) 119 | 120 | 121 | await jdbot.delete_messages(chat_id, msg) 122 | msg = await jdbot.send_message(chat_id, '开始查询账号'+text+'的资产,请稍后...') 123 | 124 | cmdtext="task "+scriptpath+" now" 125 | p = await asyncio.create_subprocess_shell( 126 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 127 | res_bytes, res_err = await p.communicate() 128 | res = res_bytes.decode('utf-8') 129 | txt=res.split('\n') 130 | strReturn="" 131 | if res: 132 | for line in txt: 133 | if "】" in line or "明细" in line: 134 | strReturn=strReturn+line+'\n' 135 | 136 | if strReturn: 137 | await jdbot.delete_messages(chat_id, msg) 138 | await jdbot.send_message(chat_id, strReturn) 139 | else: 140 | await jdbot.delete_messages(chat_id, msg) 141 | await jdbot.send_message(chat_id,'查询失败!') 142 | 143 | except Exception as e: 144 | title = "【💥错误💥】" 145 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 146 | function = "函数名:" + sys._getframe().f_code.co_name 147 | tip = '建议百度/谷歌进行查询' 148 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n\n{tip}") 149 | logger.error(f"错误--->{str(e)}") 150 | 151 | 152 | if ch_name: 153 | jdbot.add_event_handler(CCBeanInfo, events.NewMessage(from_users=chat_id, pattern=BOT_SET['命令别名']['cron'])) 154 | 155 | -------------------------------------------------------------------------------- /jbot/diy/cxjc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import os 6 | import sys 7 | import asyncio 8 | from telethon import events 9 | 10 | from .. import chat_id, jdbot, logger, ch_name, BOT_SET 11 | 12 | 13 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'^/cx$')) 14 | async def cxjc(event): 15 | try: 16 | cmd = "ps -ef" 17 | f = os.popen(cmd) 18 | txt = f.readlines() 19 | strReturn="" 20 | intcount=0 21 | if txt: 22 | for line in txt: 23 | if "timeout" in line: 24 | continue 25 | if "/ql/build" in line: 26 | continue 27 | if "/ql/static" in line: 28 | continue 29 | if "backend" in line: 30 | continue 31 | if ("node" in line and ".js" in line) or ("python3" in line and ".py" in line): 32 | parts = line.split() 33 | if len(parts) > 8: 34 | pid = parts[1].ljust(15, ' ') 35 | cmd_parts = parts[7:] 36 | cmd = " ".join(cmd_parts) 37 | cmd_split = cmd.split() 38 | if len(cmd_split) > 1 and cmd_split[0] == 'node': 39 | pid_name = cmd_split[1].split('/')[-1] 40 | else: 41 | pid = line.split()[0].ljust(15,' ') 42 | pid_name = line.split()[4] 43 | 44 | if pid_name: 45 | res ="/kill"+pid+'文件名: '+pid_name+'\n' 46 | strReturn=strReturn+res 47 | intcount=intcount+1 48 | else: 49 | continue 50 | 51 | 52 | if intcount==35: 53 | intcount=0 54 | if strReturn: 55 | await jdbot.send_message(chat_id, strReturn) 56 | strReturn="" 57 | if strReturn: 58 | await jdbot.send_message(chat_id, strReturn) 59 | else: 60 | await jdbot.send_message(chat_id,'当前系统未执行任何脚本') 61 | else: 62 | await jdbot.delete_messages(chat_id,msg) 63 | await jdbot.send_message(chat_id,'当前系统未执行任何脚本') 64 | 65 | except Exception as e: 66 | title = "【💥错误💥】" 67 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 68 | function = "函数名:" + sys._getframe().f_code.co_name 69 | tip = '建议百度/谷歌进行查询' 70 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n\n{tip}") 71 | logger.error(f"错误--->{str(e)}") 72 | 73 | 74 | if ch_name: 75 | jdbot.add_event_handler(cxjc, events.NewMessage(from_users=chat_id, pattern=BOT_SET['命令别名']['cron'])) 76 | 77 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'(/kill)')) 78 | async def pidkill(event): 79 | try: 80 | messages = event.raw_text.split("\n") 81 | for message in messages: 82 | if "kill" not in message: 83 | continue 84 | killpid = message.replace("/kill", "") 85 | 86 | #先检查是否存在该进程 87 | cmd = "ps -ef" 88 | f = os.popen(cmd) 89 | txt = f.readlines() 90 | strReturn="" 91 | matchid="" 92 | if txt: 93 | for line in txt: 94 | if "timeout" in line: 95 | continue 96 | if "/ql/build" in line: 97 | continue 98 | if "/ql/static" in line: 99 | continue 100 | if "backend" in line: 101 | continue 102 | if ("node" in line and ".js" in line) or ("python3" in line and ".py" in line): 103 | parts = line.split() 104 | if len(parts) > 8: 105 | pid = (parts[1]+"|"+parts[2]).ljust(15, ' ') 106 | else: 107 | pid = line.split()[0].ljust(15,' ') 108 | if killpid in pid: 109 | matchid=pid 110 | strReturn=strReturn+pid+" " 111 | else: 112 | continue 113 | else: 114 | await jdbot.send_message(chat_id,'当前系统未执行任何脚本') 115 | 116 | if killpid not in strReturn: 117 | await jdbot.send_message(chat_id,'进程结束失败: 当前系统未查询到该pid '+killpid+"\n进程列表:\n"+strReturn) 118 | return 119 | 120 | #存在进程则发起结束进程命令 121 | if "|" in matchid: 122 | cmd = "kill "+matchid.split("|")[1] 123 | os.system(cmd) 124 | await asyncio.sleep(1) 125 | cmd = "kill "+matchid.split("|")[0] 126 | os.system(cmd) 127 | await asyncio.sleep(1) 128 | else: 129 | cmd = "kill "+killpid 130 | os.system(cmd) 131 | await asyncio.sleep(1) 132 | 133 | #再次查询该id是否存在确认已经正常结束进程 134 | cmd = "ps -ef" 135 | f = os.popen(cmd) 136 | txt = f.readlines() 137 | strReturn="" 138 | if txt: 139 | for line in txt: 140 | if "timeout" in line: 141 | continue 142 | if "/ql/build" in line: 143 | continue 144 | if "/ql/static" in line: 145 | continue 146 | if "backend" in line: 147 | continue 148 | if ("node" in line and ".js" in line) or ("python3" in line and ".py" in line): 149 | parts = line.split() 150 | if len(parts) > 8: 151 | pid = (parts[1]+"|"+parts[2]).ljust(15, ' ') 152 | else: 153 | pid = line.split()[0].ljust(15,' ') 154 | strReturn=strReturn+pid+" " 155 | else: 156 | continue 157 | 158 | if killpid in strReturn: 159 | await jdbot.send_message(chat_id,'进程'+killpid+'强制结束失败!') 160 | else: 161 | await jdbot.send_message(chat_id,'进程'+killpid+'已被强制结束!') 162 | 163 | 164 | 165 | except Exception as e: 166 | title = "【💥错误💥】" 167 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 168 | function = "函数名:" + sys._getframe().f_code.co_name 169 | tip = '建议百度/谷歌进行查询' 170 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n\n{tip}") 171 | logger.error(f"错误--->{str(e)}") 172 | 173 | 174 | if ch_name: 175 | jdbot.add_event_handler(pidkill, events.NewMessage(from_users=chat_id, pattern=BOT_SET['命令别名']['cron'])) -------------------------------------------------------------------------------- /jbot/diy/download.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from asyncio import exceptions 6 | 7 | import os 8 | import re 9 | import requests 10 | import sys 11 | from telethon import events, Button 12 | 13 | from .. import chat_id, jdbot, CONFIG_DIR, SCRIPTS_DIR, OWN_DIR, logger, BOT_DIR, ch_name, BOT 14 | from ..bot.utils import press_event, backup_file, Remove_file, add_cron, cmd, DIY_DIR, TASK_CMD, split_list 15 | import json 16 | from ..diy.utils import mycronup, read, write 17 | 18 | 19 | @jdbot.on(events.NewMessage(from_users=chat_id, pattern=r'^https?://.*(js|py|sh)$')) 20 | async def mydownload(event): 21 | try: 22 | SENDER = event.sender_id 23 | furl = event.raw_text 24 | if '下载代理' in BOT.keys() and str(BOT['下载代理']).lower() != 'false' and 'github' in furl: 25 | furl = f'{str(BOT["下载代理"])}/{furl}' 26 | try: 27 | resp = requests.get(furl).text 28 | if "" in resp: 29 | await jdbot.send_message(chat_id, f"接收到的[链接]({furl})是一个页面并非raw数据,会话结束") 30 | return 31 | except Exception as e: 32 | await jdbot.send_message(chat_id, f"下载失败\n{e}") 33 | return 34 | 35 | runcmd="" 36 | async with jdbot.conversation(SENDER, timeout=60) as conv: 37 | fname = furl.split('/')[-1] 38 | filename=fname 39 | fname_cn = '' 40 | if furl.endswith(".js"): 41 | fname_cn = re.findall(r"(?<=new\sEnv\(').*(?=')", resp, re.M) 42 | if fname_cn != []: 43 | fname_cn = fname_cn[0] 44 | else: 45 | fname_cn = '' 46 | 47 | btn = [] 48 | 49 | issetconfig=False 50 | if os.path.exists("/ql/data/config/auth.json"): 51 | configpath="/ql/data/" 52 | 53 | if os.path.exists("/ql/config/auth.json"): 54 | configpath="/ql/" 55 | 56 | if os.path.exists("/jd/config/config.sh"): 57 | configpath="/jd/" 58 | 59 | try: 60 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 61 | ccbotSetting = json.loads(f.read()) 62 | f.close() 63 | for key in ccbotSetting: 64 | if key=="文件存放配置": 65 | issetconfig=True 66 | except Exception as e: 67 | await jdbot.send_message(chat_id,f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 68 | return 69 | 70 | if not issetconfig: 71 | await jdbot.send_message(chat_id, f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 72 | return 73 | 74 | getfileSettinglist=ccbotSetting["文件存放配置"] 75 | 76 | countbtn=3 77 | for fileSetting in getfileSettinglist: 78 | if fileSetting["按钮名字"]=="配置档": 79 | countbtn=int(fileSetting["每行按钮数"]) 80 | else: 81 | btn.append(Button.inline(fileSetting["按钮名字"], data=fileSetting["按钮名字"]+"|"+fileSetting["存放路径"])) 82 | btn.append(Button.inline('取消', data='取消|cancel')) 83 | btn = split_list(btn, countbtn) 84 | 85 | cmdtext = False 86 | msg = await conv.send_message(f'成功下载{fname_cn}脚本\n现在,请做出你的选择:', buttons=btn) 87 | convdata = await conv.wait_event(press_event(SENDER)) 88 | res = bytes.decode(convdata.data) 89 | isbackup="1" 90 | noaskaddcron="0" 91 | 92 | for fileSetting in getfileSettinglist: 93 | if fileSetting["按钮名字"]=="配置档": 94 | continue 95 | if fileSetting["按钮名字"]==res.split("|")[0]: 96 | isbackup=fileSetting["备份原脚本"] 97 | for key in fileSetting: 98 | if "执行命令" in key: 99 | if runcmd!="" : 100 | runcmd=runcmd+"\n" 101 | runcmd=runcmd+fileSetting[key].replace("文件名",filename) 102 | if "不问是否定时" in key: 103 | noaskaddcron=fileSetting[key] 104 | isrun="0" 105 | res=res.split("|")[1] 106 | if "task " in res: 107 | isrun="1" 108 | res=res.replace("task ","") 109 | 110 | markup = [Button.inline('是', data='yes'), 111 | Button.inline('否', data='no')] 112 | if res == 'cancel': 113 | msg = await jdbot.edit_message(msg, '对话已取消') 114 | conv.cancel() 115 | return 116 | else: 117 | res2="" 118 | if noaskaddcron=="0": 119 | msg = await jdbot.edit_message(msg, '是否尝试自动加入定时', buttons=markup) 120 | convdata2 = await conv.wait_event(press_event(SENDER)) 121 | res2 = bytes.decode(convdata2.data) 122 | 123 | if isbackup=="1": 124 | backup_file(f'{res}/{filename}') 125 | else: 126 | Remove_file(f'{res}/{filename}') 127 | 128 | if isrun=="1": 129 | cmdtext = f'{TASK_CMD} {res}/{filename} now' 130 | 131 | with open(f'{res}/{filename}', 'w+', encoding='utf-8') as f: 132 | f.write(resp) 133 | 134 | if res2 == 'yes': 135 | await add_cron(jdbot, conv, resp, filename, msg, SENDER, markup, res) 136 | else: 137 | await jdbot.edit_message(msg, f'{filename}已保存到{res}文件夹') 138 | conv.cancel() 139 | if cmdtext: 140 | if runcmd!="": 141 | runcmd=cmdtext+"\n"+runcmd 142 | else: 143 | runcmd=cmdtext 144 | 145 | if runcmd!="": 146 | msg=await jdbot.send_message(chat_id,"开始执行命令列表"+":\n"+runcmd) 147 | cmdlist=runcmd.split("\n") 148 | for RunCommound in cmdlist: 149 | await cmd(RunCommound) 150 | 151 | await jdbot.edit_message(msg, '任务执行完毕,祝君愉快.') 152 | 153 | except exceptions.TimeoutError: 154 | await jdbot.edit_message(msg, '选择已超时,对话已停止,感谢你的使用') 155 | except Exception as e: 156 | title = "【💥错误💥】" 157 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 158 | function = "函数名:" + sys._getframe().f_code.co_name 159 | tip = '建议百度/谷歌进行查询' 160 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n\n{tip}") 161 | logger.error(f"错误--->{str(e)}") 162 | 163 | 164 | if ch_name: 165 | jdbot.add_event_handler(mydownload, events.NewMessage(from_users=chat_id, pattern=BOT['命令别名']['cron'])) 166 | 167 | -------------------------------------------------------------------------------- /jbot/user/bean_Global.py: -------------------------------------------------------------------------------- 1 | from PIL import Image, ImageFont, ImageDraw 2 | from telethon import events, Button 3 | from .. import LOG_DIR, jdbot, chat_id, BOT_SET, BOT_DIR, logger, ch_name 4 | from prettytable import PrettyTable 5 | import subprocess 6 | from ..bot.beandata import get_bean_data 7 | from ..bot.utils import V4,split_list, press_event 8 | from uuid import uuid4 9 | from .login import user 10 | 11 | BEAN_IN_FILE = f'{LOG_DIR}/bean_income-{uuid4()}.csv' 12 | BEAN_OUT_FILE = f'{LOG_DIR}/bean_outlay-{uuid4()}.csv' 13 | BEAN_TOTAL_FILE = f'{LOG_DIR}/bean_total-{uuid4()}.csv' 14 | BEAN_IMG = f'{LOG_DIR}/bean-{uuid4()}.jpg' 15 | FONT_FILE = f'{BOT_DIR}/font/jet.ttf' 16 | 17 | 18 | @user.on(events.NewMessage(pattern=r'^bb', outgoing=True)) 19 | async def bot_bean(event): 20 | msg_text= event.raw_text.split(' ') 21 | if isinstance(msg_text, list) and len(msg_text) == 2: 22 | text = msg_text[-1] 23 | else: 24 | text = None 25 | 26 | if text==None: 27 | await event.edit('请指定要查询的账号,格式: bb 1 或 bb ptpin') 28 | return 29 | else: 30 | await event.edit('开始查询账号'+text+'的资产,请稍后...') 31 | 32 | if V4 and text == 'in': 33 | subprocess.check_output( 34 | 'jcsv', shell=True, stderr=subprocess.STDOUT) 35 | creat_bean_counts(BEAN_IN_FILE) 36 | await event.delete() 37 | await user.send_message(event.chat_id, '您的近日收入情况', file=BEAN_IMG) 38 | 39 | elif V4 and text == 'out': 40 | subprocess.check_output( 41 | 'jcsv', shell=True, stderr=subprocess.STDOUT) 42 | creat_bean_counts(BEAN_OUT_FILE) 43 | await event.delete() 44 | await user.send_message(event.chat_id, '您的近日支出情况', file=BEAN_IMG) 45 | 46 | elif not V4 and (text == 'in' or text == 'out' or text is None): 47 | await event.delete() 48 | await user.send_message(event.chat_id,'QL暂不支持使用bean in、out ,请使用/bean n n为数字') 49 | 50 | elif text and int(text): 51 | res = get_bean_data(int(text)) 52 | if res['code'] != 200: 53 | await event.delete() 54 | await user.send_message(event.chat_id, f'something wrong,I\'m sorry\n{str(res["data"])}') 55 | else: 56 | creat_bean_count(res['data'][3], res['data'][0], res['data'][1], res['data'][2][1:]) 57 | await event.delete() 58 | await user.send_message(event.chat_id, f'您的账号{text}收支情况', file=BEAN_IMG) 59 | elif not text: 60 | subprocess.check_output( 61 | 'jcsv', shell=True, stderr=subprocess.STDOUT) 62 | creat_bean_counts(BEAN_TOTAL_FILE) 63 | await event.delete() 64 | await user.send_message(event.chat_id, '您的总京豆情况', file=BEAN_IMG) 65 | else: 66 | await event.delete() 67 | await user.send_message(event.chat_id, '青龙暂仅支持/bean n n为账号数字') 68 | 69 | 70 | def creat_bean_count(date, beansin, beansout, beanstotal): 71 | tb = PrettyTable() 72 | tb.add_column('DATE', date) 73 | tb.add_column('BEANSIN', beansin) 74 | tb.add_column('BEANSOUT', beansout) 75 | tb.add_column('TOTAL', beanstotal) 76 | font = ImageFont.truetype(FONT_FILE, 18) 77 | im = Image.new("RGB", (500, 260), (244, 244, 244)) 78 | dr = ImageDraw.Draw(im) 79 | dr.text((10, 5), str(tb), font=font, fill="#000000") 80 | im.save(BEAN_IMG) 81 | 82 | 83 | def creat_bean_counts(csv_file): 84 | with open(csv_file, 'r', encoding='utf-8') as f: 85 | data = f.readlines() 86 | tb = PrettyTable() 87 | num = len(data[-1].split(',')) - 1 88 | title = ['DATE'] 89 | for i in range(0, num): 90 | title.append('COUNT'+str(i+1)) 91 | tb.field_names = title 92 | data = data[-7:] 93 | for line in data: 94 | row = line.split(',') 95 | if len(row) > len(title): 96 | row = row[:len(title)] 97 | elif len(row) < len(title): 98 | i = len(title) - len(row) 99 | for _ in range(0, i): 100 | row.append(str(0)) 101 | tb.add_row(row) 102 | length = 172 + 100 * num 103 | im = Image.new("RGB", (length, 400), (244, 244, 244)) 104 | dr = ImageDraw.Draw(im) 105 | font = ImageFont.truetype(FONT_FILE, 18) 106 | dr.text((10, 5), str(tb), font=font, fill="#000000") 107 | im.save(BEAN_IMG) 108 | -------------------------------------------------------------------------------- /jbot/user/beaninfo_Global.py: -------------------------------------------------------------------------------- 1 | from telethon import events 2 | from .. import jdbot,chat_id, logger 3 | from ..diy.utils import read, write 4 | import asyncio 5 | import re 6 | import os 7 | import json 8 | try: 9 | from .login import user 10 | except: 11 | from .. import user 12 | 13 | @user.on(events.NewMessage(pattern=r'^setbd', outgoing=True)) 14 | async def SetBeanDetailInfo(event): 15 | try: 16 | msg_text= event.raw_text.split(' ') 17 | if len(msg_text) == 2: 18 | text = msg_text[-1] 19 | else: 20 | text = None 21 | 22 | if text==None: 23 | await event.edit('请输入正确的格式: setbd 屏蔽京豆数量') 24 | return 25 | 26 | key="BOTShowTopNum" 27 | kv=f'{key}="{text}"' 28 | change="" 29 | configs = read("str") 30 | if kv not in configs: 31 | if key in configs: 32 | configs = re.sub(f'{key}=("|\').*("|\')', kv, configs) 33 | write(configs) 34 | else: 35 | configs = read("str") 36 | configs += f'export {key}="{text}"\n' 37 | write(configs) 38 | change = f'已替换屏蔽京豆数为{text}' 39 | else: 40 | change = f'设定没有改变,想好再来.' 41 | 42 | await event.edit(change) 43 | 44 | except Exception as e: 45 | title = "【💥错误💥】" 46 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 47 | function = "函数名:" + e.__traceback__.tb_frame.f_code.co_name 48 | details = "错误详情:第 " + str(e.__traceback__.tb_lineno) + " 行" 49 | tip = '建议百度/谷歌进行查询' 50 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n{details}\n{traceback.format_exc()}\n{tip}") 51 | logger.error(f"错误--->{str(e)}") 52 | 53 | @user.on(events.NewMessage(pattern=r'^bd', outgoing=True)) 54 | async def CCBeanDetailInfo(event): 55 | msg_text= event.raw_text.split(' ') 56 | if len(msg_text) == 2: 57 | text = msg_text[-1] 58 | else: 59 | text = None 60 | 61 | if text==None: 62 | await event.edit('请指定要查询的账号,格式: bd 1 或 bd ptpin') 63 | return 64 | 65 | 66 | #载入设定 67 | scriptpath="" 68 | waitsec=0 69 | issetconfig=False 70 | showtopnum=0 71 | if os.path.exists("/ql/data/config/auth.json"): 72 | configpath="/ql/data/" 73 | 74 | if os.path.exists("/ql/config/auth.json"): 75 | configpath="/ql/" 76 | 77 | if os.path.exists("/jd/config/config.sh"): 78 | configpath="/jd/" 79 | 80 | try: 81 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 82 | ccbotSetting = json.loads(f.read()) 83 | f.close() 84 | for key in ccbotSetting: 85 | if key=="bd命令配置": 86 | issetconfig=True 87 | except Exception as e: 88 | await event.edit(f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 89 | return 90 | 91 | if not issetconfig: 92 | await event.edit(f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 93 | return 94 | 95 | try: 96 | for key in ccbotSetting["bd命令配置"]: 97 | if key=="脚本文件地址": 98 | scriptpath=ccbotSetting["bd命令配置"][key] 99 | if key=="多少秒后自动删除": 100 | waitsec=int(ccbotSetting["bd命令配置"][key]) 101 | if key=="近期京豆展示的条数": 102 | showtopnum=int(ccbotSetting["bd命令配置"][key]) 103 | except Exception as e: 104 | await event.edit(f'载入ccbotSetting.json的bd命令配置内容出错,请检查!\n'+str(e)) 105 | return 106 | 107 | if scriptpath=="": 108 | await event.edit(f'ccbotSetting.json中的bd命令配置没有填写脚本文件地址,请检查!') 109 | return 110 | 111 | if not os.path.exists(scriptpath): 112 | await event.edit(f'ccbotSetting.json中的bd命令配置的脚本文件不存在,请检查!\n'+scriptpath) 113 | return 114 | 115 | key="BOTCHECKCODE" 116 | kv=f'{key}="{text}"' 117 | configs = read("str") 118 | intcount=0 119 | if kv not in configs: 120 | if key in configs: 121 | configs = re.sub(f'{key}=("|\').*("|\')', kv, configs) 122 | write(configs) 123 | else: 124 | configs = read("str") 125 | configs += f'\nexport {key}="{text}"\n' 126 | write(configs) 127 | 128 | key="BOTShowJinQiNum" 129 | kv=f'{key}="{showtopnum}"' 130 | configs = read("str") 131 | intcount=0 132 | if kv not in configs: 133 | if key in configs: 134 | configs = re.sub(f'{key}=("|\').*("|\')', kv, configs) 135 | write(configs) 136 | else: 137 | configs = read("str") 138 | configs += f'\nexport {key}="{showtopnum}"\n' 139 | write(configs) 140 | 141 | 142 | await event.edit('开始查询账号'+text+'的资产,请稍后...') 143 | 144 | cmdtext="task "+scriptpath+" now" 145 | p = await asyncio.create_subprocess_shell( 146 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 147 | res_bytes, res_err = await p.communicate() 148 | res = res_bytes.decode('utf-8') 149 | txt=res.split('\n') 150 | result="" 151 | if res: 152 | for line in txt: 153 | if "近期豆子" in line: 154 | result=result+'\n' 155 | if "【" in line and "🔔" not in line: 156 | result=result+line+'\n' 157 | else: 158 | result='查询失败!\n' 159 | 160 | if waitsec==0: 161 | await event.edit(result) 162 | else: 163 | result=result+"\n【本条信息将在"+str(waitsec)+"秒钟后自动删除】" 164 | await event.edit(result) 165 | await asyncio.sleep(waitsec) 166 | await event.delete() 167 | -------------------------------------------------------------------------------- /jbot/user/ccbean_Global.py: -------------------------------------------------------------------------------- 1 | from telethon import events 2 | from ..diy.utils import read, write 3 | import asyncio 4 | import re 5 | import os 6 | import json 7 | try: 8 | from .login import user 9 | except: 10 | from .. import user 11 | 12 | @user.on(events.NewMessage(pattern=r'^cb', outgoing=True)) 13 | async def CCBeanInfo(event): 14 | msg_text= event.raw_text.split(' ') 15 | if isinstance(msg_text, list) and len(msg_text) == 2: 16 | text = msg_text[-1] 17 | else: 18 | text = None 19 | 20 | if text==None: 21 | await event.edit('请指定要查询的账号,格式: cb 1 或 cb ptpin') 22 | return 23 | 24 | #载入设定 25 | scriptpath="" 26 | waitsec=0 27 | issetconfig=False 28 | nocheck="" 29 | if os.path.exists("/ql/data/config/auth.json"): 30 | configpath="/ql/data/" 31 | 32 | if os.path.exists("/ql/config/auth.json"): 33 | configpath="/ql/" 34 | 35 | if os.path.exists("/jd/config/config.sh"): 36 | configpath="/jd/" 37 | 38 | try: 39 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 40 | ccbotSetting = json.loads(f.read()) 41 | f.close() 42 | for key in ccbotSetting: 43 | if key=="cb命令配置": 44 | issetconfig=True 45 | except Exception as e: 46 | await event.edit(f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 47 | return 48 | 49 | if not issetconfig: 50 | await event.edit(f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 51 | return 52 | 53 | try: 54 | for key in ccbotSetting["cb命令配置"]: 55 | if key=="脚本文件地址": 56 | scriptpath=ccbotSetting["cb命令配置"][key] 57 | if key=="多少秒后自动删除": 58 | waitsec=int(ccbotSetting["cb命令配置"][key]) 59 | if key=="关闭查询项目": 60 | nocheck=ccbotSetting["cb命令配置"][key] 61 | except Exception as e: 62 | await event.edit(f'载入ccbotSetting.json的cb命令配置内容出错,请检查!\n'+str(e)) 63 | return 64 | 65 | if scriptpath=="": 66 | await event.edit(f'ccbotSetting.json中的cb命令配置没有填写脚本文件地址,请检查!') 67 | return 68 | 69 | if not os.path.exists(scriptpath): 70 | await event.edit(f'ccbotSetting.json中的cb命令配置的脚本文件不存在,请检查!\n'+scriptpath) 71 | return 72 | 73 | 74 | key="BOTCHECKCODE" 75 | kv=f'{key}="{text}"' 76 | configs = read("str") 77 | if kv not in configs: 78 | if key in configs: 79 | configs = re.sub(f'{key}=("|\').*("|\')', kv, configs) 80 | write(configs) 81 | else: 82 | configs = read("str") 83 | configs += f'\nexport {key}="{text}"\n' 84 | write(configs) 85 | 86 | key="BEANCHANGE_BOTDISABLELIST" 87 | kv=f'{key}="{nocheck}"' 88 | configs = read("str") 89 | if kv not in configs: 90 | if key in configs: 91 | configs = re.sub(f'{key}=("|\').*("|\')', kv, configs) 92 | write(configs) 93 | else: 94 | configs = read("str") 95 | configs += f'\nexport {key}="{nocheck}"\n' 96 | write(configs) 97 | 98 | 99 | await event.edit('开始查询账号'+text+'的资产,请稍后...') 100 | 101 | cmdtext="task "+scriptpath+" now" 102 | p = await asyncio.create_subprocess_shell( 103 | cmdtext, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) 104 | res_bytes, res_err = await p.communicate() 105 | res = res_bytes.decode('utf-8') 106 | txt=res.split('\n') 107 | result="" 108 | if res: 109 | for line in txt: 110 | if "】" in line or "明细" in line: 111 | result=result+line+'\n' 112 | 113 | if result=="": 114 | result='查询失败!' 115 | 116 | if waitsec==0: 117 | await event.edit(result) 118 | else: 119 | result=result+"\n【本条信息将在"+str(waitsec)+"秒钟后自动删除】" 120 | await event.edit(result) 121 | await asyncio.sleep(waitsec) 122 | await event.delete() -------------------------------------------------------------------------------- /jbot/user/chart_Global.py: -------------------------------------------------------------------------------- 1 | from telethon import events, Button 2 | from .. import jdbot, chat_id, LOG_DIR, logger, BOT_SET, ch_name 3 | from ..bot.quickchart import QuickChart, QuickChartFunction 4 | from ..bot.beandata import get_bean_data 5 | from ..bot.utils import V4,split_list, press_event 6 | from uuid import uuid4 7 | from .login import user 8 | 9 | BEAN_IMG = f'{LOG_DIR}/bot/bean-{uuid4()}.jpg' 10 | 11 | @user.on(events.NewMessage(pattern=r'^bc', outgoing=True)) 12 | async def my_chartinfo(event): 13 | msg_text= event.raw_text.split(' ') 14 | if isinstance(msg_text, list) and len(msg_text) == 2: 15 | text = msg_text[-1] 16 | else: 17 | text = None 18 | 19 | if text==None: 20 | await event.edit('请指定要查询的账号,格式: bc 1 或 bc ptpin') 21 | return 22 | else: 23 | await event.edit('开始查询账号'+text+'的资产,请稍后...') 24 | 25 | if text and int(text): 26 | res = get_bean_data(int(text)) 27 | if res['code'] != 200: 28 | await event.delete() 29 | await user.send_message(event.chat_id,f'something wrong,I\'m sorry\n{str(res["data"])}') 30 | else: 31 | aver = (res["data"][0][0]+res["data"][0][1]+res["data"][0][2]+res["data"][0][3]+res["data"][0][4]+res["data"][0][5]+res["data"][0][6])//7 32 | nickname=res['data'][4] 33 | createChart(res['data'][0],res['data'][1],f' {nickname} · 近七天平均收入{aver}豆⚡',res['data'][3],text) 34 | await event.delete() 35 | await user.send_message(event.chat_id,f'您的账号{text}收支情况',file=BEAN_IMG) 36 | 37 | 38 | def createChart(income,out,Title,label,text): 39 | qc = QuickChart() 40 | qc.width=1000 41 | qc.height=500 42 | qc.background_color="#22252a" 43 | qc.config = { 44 | "data": { 45 | "datasets": [{ 46 | "backgroundColor": QuickChartFunction('getGradientFillHelper(\'vertical\', ["#faab2c", "#f48847", "#ef5d68"])'), 47 | "data": income, 48 | "label": "收入", 49 | "type": "bar" 50 | }, 51 | { 52 | "backgroundColor": QuickChartFunction('getGradientFillHelper(\'vertical\', ["#777777", "#747474"])'), 53 | "data": out, 54 | "label": "支出", 55 | "type": "bar" 56 | } 57 | ], 58 | "labels": label 59 | }, 60 | "options": { 61 | "plugins": { 62 | "datalabels": { 63 | "display": True, 64 | "color": "#eee", 65 | "align": "top", 66 | "offset": -4, 67 | "anchor": "end", 68 | "font": { 69 | "family": "Helvetica Neue", 70 | "size": 16 71 | } 72 | } 73 | }, 74 | "legend": { 75 | "position": "bottom", 76 | "align": "end", 77 | "display": True 78 | }, 79 | "layout": { 80 | "padding": { 81 | "left": 10, 82 | "right": 20, 83 | "top": 30, 84 | "bottom": 15 85 | } 86 | }, 87 | "responsive": True, 88 | "title": { 89 | "display": True, 90 | "position": "bottom", 91 | "text": Title, 92 | "fontSize": 20, 93 | "fontColor": "#aaa" 94 | }, 95 | "tooltips": { 96 | "intersect": True, 97 | "mode": "index" 98 | }, 99 | "scales": { 100 | "xAxes": [{ 101 | "gridLines": { 102 | "display": True, 103 | "color": "" 104 | }, 105 | "ticks": { 106 | "display": True, 107 | "fontSize": 16, 108 | "fontColor": "#999" 109 | } 110 | }], 111 | "yAxes": [{ 112 | "gridLines": { 113 | "display": True, 114 | "color": "" 115 | }, 116 | "ticks": { 117 | "display": True, 118 | "fontSize": 14, 119 | "fontColor": "#999" 120 | } 121 | }] 122 | } 123 | }, 124 | "type": "bar" 125 | } 126 | qc.to_file(BEAN_IMG) -------------------------------------------------------------------------------- /jbot/user/jinffen_Global.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import asyncio 5 | import datetime 6 | import os 7 | import json 8 | import re 9 | import time 10 | from random import sample 11 | import httpx 12 | from telethon import events 13 | from .. import jdbot,chat_id,logger 14 | from ..bot.utils import get_cks 15 | from urllib.parse import unquote 16 | 17 | try: 18 | from .login import user 19 | except: 20 | from .. import user 21 | 22 | @user.on(events.NewMessage(pattern=r'^jf', outgoing=True)) 23 | async def getyj(event): 24 | try: 25 | msg_text= event.raw_text.split(' ') 26 | if isinstance(msg_text, list) and len(msg_text) == 2: 27 | text = msg_text[-1] 28 | else: 29 | text = None 30 | 31 | if text==None: 32 | await event.edit('请指定要查询的账号,格式: jf ck数') 33 | return 34 | else: 35 | await event.edit("开始查询") 36 | 37 | #载入设定 38 | waitsec=0 39 | issetconfig=False 40 | 41 | if os.path.exists("/ql/data/config/auth.json"): 42 | configpath="/ql/data/" 43 | ckfile="/ql/data/config/auth.json" 44 | 45 | if os.path.exists("/ql/config/auth.json"): 46 | configpath="/ql/" 47 | ckfile="/ql/config/auth.json" 48 | 49 | if os.path.exists("/jd/config/config.sh"): 50 | configpath="/jd/" 51 | ckfile="" 52 | 53 | if ckfile=="": 54 | await event.edit('不支持V4环境,退出...') 55 | return 56 | 57 | try: 58 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 59 | ccbotSetting = json.loads(f.read()) 60 | f.close() 61 | for key in ccbotSetting: 62 | if key=="jf命令配置": 63 | issetconfig=True 64 | except Exception as e: 65 | await event.edit(f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 66 | return 67 | 68 | if not issetconfig: 69 | await event.edit(f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 70 | return 71 | 72 | try: 73 | for key in ccbotSetting["jf命令配置"]: 74 | if key=="多少秒后自动删除": 75 | waitsec=int(ccbotSetting["jf命令配置"][key]) 76 | except Exception as e: 77 | await event.edit(f'载入ccbotSetting.json的bd命令配置内容出错,请检查!\n'+str(e)) 78 | return 79 | 80 | num = int(text) 81 | 82 | cookies = get_cks(ckfile) 83 | if num > len(cookies): 84 | info = f'查询失败,您共有{len(cookies)}个账号' 85 | else: 86 | jfck = cookies[num - 1] 87 | pin = re.findall(r'(pt_pin=([^; ]+)(?=;?))',jfck)[0][1] 88 | if re.search('%', pin): 89 | pin = unquote(pin, 'utf-8') 90 | logger.error(jfck) 91 | start = datetime.datetime.now().strftime('%Y-%m-%d %H:%M') 92 | #info = f'以下是{pin}的京粉信息:\n' 93 | 94 | 95 | yesterday = (datetime.datetime.now() + datetime.timedelta(days=-1)).strftime("%Y-%m-%d") 96 | sevendate = (datetime.datetime.now() + datetime.timedelta(days=-7)).strftime("%Y-%m-%d") 97 | now = datetime.datetime.now() 98 | last_month = now - datetime.timedelta(days=now.day) 99 | first_day_of_this_month = datetime.datetime(now.year, now.month, 1) 100 | last_day = datetime.datetime(last_month.year, last_month.month, 1) 101 | last_day_of_last_month = first_day_of_this_month - datetime.timedelta(days=1) 102 | 103 | jfflinfo,jfflclickinfo,jfdata, get_ztmy, get_7my, get_thismonth,get_lastmonth = await asyncio.gather( 104 | get_flinfo(jfck), 105 | get_flclickinfo(jfck), 106 | get_fl(jfck), 107 | get_fls(jfck, yesterday,yesterday), 108 | get_fls(jfck, sevendate,yesterday), 109 | get_fls(jfck, first_day_of_this_month.strftime("%Y-%m-%d"),yesterday), 110 | get_fls(jfck, last_day.strftime("%Y-%m-%d"),last_day_of_last_month.strftime("%Y-%m-%d")) 111 | ) 112 | 113 | if jfflinfo['code'] == 200 and jfflclickinfo['code'] == 200 and jfdata['code'] == 200 and get_ztmy['code'] == 200 and get_7my['code'] == 200 and get_thismonth['code'] == 200 and get_lastmonth['code'] == 200: 114 | yj = 0 115 | count = 0 116 | keys = ['待付款', '取消'] 117 | for i in jfdata['data']: 118 | if all(k not in str(i['validCodeMsg']) for k in keys) and float(i['estimateFee']) > 0: 119 | yj += i['estimateFee'] 120 | count += 1 121 | info = f'【{pin}今日京粉信息】\n' 122 | info += f' 【截止到{start}】\n' 123 | info += f' 【点击量】{jfflclickinfo["data"]["clickCount"]}\n 【引入UV】{jfflclickinfo["data"]["introduceUv"]}\n 【有效订单量】{jfflclickinfo["data"]["validOrderCount"]}\n' 124 | info += f' 【有效订单金额】{jfflclickinfo["data"]["validOrderAmount"]}\n 【预估收入】{jfflclickinfo["data"]["predictCommission"]}\n' 125 | info += f'\n【实时统计信息】\n' 126 | info += f' 【昨日佣金】{get_ztmy["data"]}\n 【七日收入】{get_7my["data"]}\n 【本月收入】{get_thismonth["data"]}\n 【上月收入】{get_lastmonth["data"]}\n' 127 | info += f'\n【系统结算信息】\n' 128 | info += f' 【本月预估结算】{jfflinfo["data"]["lastMonthAmount"]}\n 【下月预估结算】{jfflinfo["data"]["thisMonthAmount"]}' 129 | 130 | elif 'no login' in jfdata['data']: 131 | info += f'查询失败,{pin}账号已过期' 132 | elif 'no register' in jfdata['data']: 133 | info += f'查询失败,{pin}返利未激活' 134 | else: 135 | info += f'查询出错,{pin}错误详情\n{jfdata["data"], get_ztmy["data"], get_7my["data"]}' 136 | 137 | 138 | if waitsec==0: 139 | await event.edit(info) 140 | else: 141 | info=info+"\n\n【本条信息将在"+str(waitsec)+"秒钟后自动删除】" 142 | await event.edit(info) 143 | await asyncio.sleep(waitsec) 144 | await event.delete() 145 | 146 | except Exception as e: 147 | title = "【💥错误💥】" 148 | name = "文件名:" + os.path.split(__file__)[-1].split(".")[0] 149 | function = "函数名:" + e.__traceback__.tb_frame.f_code.co_name 150 | details = "错误详情:第 " + str(e.__traceback__.tb_lineno) + " 行" 151 | await jdbot.send_message(chat_id, f"{title}\n\n{name}\n{function}\n错误原因:{str(e)}\n{details}") 152 | logger.error(f"错误--->{str(e)}") 153 | 154 | 155 | async def get_fl(cookie): 156 | try: 157 | dnow = (datetime.datetime.now() + datetime.timedelta(days=-1)).strftime('%Y-%m-%d %H:%M:%S') 158 | dtnow = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 159 | body = { 160 | "funName": "listOrderSku", 161 | "unionId": "", 162 | "param": { 163 | "startTime": dnow, 164 | "endTime": dtnow, 165 | "orderStatus": 0, 166 | "optType": 1, 167 | "unionRole": 1 168 | }, 169 | "page": { 170 | "pageNo": 1, 171 | "pageSize": 100 172 | } 173 | } 174 | url = f'https://api.m.jd.com/api?functionId=listOrderSku&_={dtnow}&appid=u&body={body}&loginType=2' 175 | headers = { 176 | 'Host': 'api.m.jd.com', 177 | 'Accept': '*/*', 178 | 'Accept-Encoding': 'gzip, deflate, br', 179 | 'Accept-Language': 'zh-cn', 180 | 'Connection': 'keep-alive', 181 | 'Content-Type': 'application/json', 182 | 'cookie': cookie, 183 | 'Referer': 'https://jingfenapp.jd.com', 184 | 'User-Agent': await userAgent() 185 | } 186 | async with httpx.AsyncClient(verify=False) as session: 187 | res = await session.get(url, headers=headers) 188 | if res.status_code == 200 and res.json().get('code') == 200: 189 | jforder, estimateFee, validCodeMsg = [], [], [] 190 | dnow = datetime.datetime.now().strftime('%Y-%m-%d') 191 | dnow_reg = re.compile(dnow) 192 | jforders = res.json()['result'] 193 | for order in jforders: 194 | if re.search(dnow_reg, order['orderTime']): 195 | jforder.append(order['orderId']) 196 | estimateFee.append(order['estimateFee']) 197 | validCodeMsg.append(order['validCodeMsg']) 198 | jflist = [] 199 | mid = map(list, zip(jforder, estimateFee, validCodeMsg)) 200 | for item in mid: 201 | jfdict = dict(zip(['jforder', 'estimateFee', 'validCodeMsg'], item)) 202 | jflist.append(jfdict) 203 | return {'code': 200, 'data': jflist} 204 | else: 205 | return {'code': 400, 'data': str(res.json())} 206 | except Exception as e: 207 | return {'code': 400, 'data': e} 208 | 209 | 210 | async def get_fls(cookie, startdate,enddate): 211 | try: 212 | body = {"funName": "querySpreadEffectData", "unionId": 2023952562, "param": {"startDate": startdate, "endDate": enddate}} 213 | url = f"https://api.m.jd.com/api?functionId=union_report&_={int(time.time() * 1000)}&appid=u&body={body}&loginType=2" 214 | headers = { 215 | 'Host': 'api.m.jd.com', 216 | 'Connection': 'keep-alive', 217 | 'Cookie': cookie, 218 | 'content-type': 'application/json', 219 | 'Accept-Encoding': 'gzip,compress,br,deflate', 220 | 'User-Agent': await userAgent(), 221 | 'Referer': 'https://servicewechat.com/wxf463e50cd384beda/138/page-frame.html' 222 | } 223 | async with httpx.AsyncClient(verify=False) as session: 224 | res = await session.get(url, headers=headers, timeout=10) 225 | if res.status_code == 200: 226 | response = res.json()["result"]["spreadReportInfoSum"]["cosFee"] 227 | return {'code': 200, 'data': response} 228 | else: 229 | return {'code': 400, 'data': str(res.json())} 230 | except Exception as e: 231 | return {'code': 400, 'data': e} 232 | 233 | 234 | async def get_flinfo(cookie): 235 | try: 236 | body = {"funName": "queryYgCommTotal"} 237 | url = f"https://api.m.jd.com/api?functionId=union_balance_pay&_={int(time.time() * 1000)}&appid=u&body={body}&loginType=2" 238 | headers = { 239 | 'Host': 'api.m.jd.com', 240 | 'Connection': 'keep-alive', 241 | 'Cookie': cookie, 242 | 'content-type': 'application/json', 243 | 'Accept-Encoding': 'gzip,compress,br,deflate', 244 | 'User-Agent': await userAgent(), 245 | 'Referer': 'https://servicewechat.com/wxf463e50cd384beda/138/page-frame.html' 246 | } 247 | async with httpx.AsyncClient(verify=False) as session: 248 | res = await session.get(url, headers=headers, timeout=10) 249 | 250 | if res.status_code == 200: 251 | response = res.json()["result"] 252 | return {'code': 200, 'data': response} 253 | else: 254 | return {'code': 400, 'data': str(res.json())} 255 | except Exception as e: 256 | return {'code': 400, 'data': e} 257 | 258 | async def get_flclickinfo(cookie): 259 | try: 260 | dtnow = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') 261 | body = {"funName":"getIndexStatisticsInfoList","param":{"startTime":dtnow,"endTime":dtnow}} 262 | url = f"https://api.m.jd.com/api?functionId=union_data_bi_shop&_={int(time.time() * 1000)}&appid=u_jfapp&body={body}&loginType=2" 263 | headers = { 264 | 'Host': 'api.m.jd.com', 265 | 'Connection': 'keep-alive', 266 | 'Cookie': cookie, 267 | 'content-type': 'application/json', 268 | 'Accept-Encoding': 'gzip,compress,br,deflate', 269 | 'User-Agent': await userAgent(), 270 | 'Referer': 'https://jingfenapp.jd.com/' 271 | } 272 | async with httpx.AsyncClient(verify=False) as session: 273 | res = await session.get(url, headers=headers, timeout=10) 274 | 275 | if res.status_code == 200: 276 | response = res.json()["result"] 277 | return {'code': 200, 'data': response} 278 | else: 279 | return {'code': 400, 'data': str(res.json())} 280 | except Exception as e: 281 | return {'code': 400, 'data': e} 282 | 283 | async def userAgent(): 284 | """ 285 | 随机生成一个UA 286 | """ 287 | uuid = ''.join(sample('123456789abcdef123456789abcdef123456789abcdef123456789abcdef', 40)) 288 | addressid = ''.join(sample('1234567898647', 10)) 289 | iosVer = ''.join(sample(["14.5.1", "14.4", "14.3", "14.2", "14.1", "14.0.1", "13.7", "13.1.2", "13.1.1"], 1)) 290 | iosV = iosVer.replace('.', '_') 291 | iPhone = ''.join(sample(["8", "9", "10", "11", "12", "13"], 1)) 292 | ADID = ''.join(sample('0987654321ABCDEF', 8)) + '-' + ''.join(sample('0987654321ABCDEF', 4)) + '-' + ''.join(sample('0987654321ABCDEF', 4)) + '-' + ''.join(sample('0987654321ABCDEF', 4)) + '-' + ''.join(sample('0987654321ABCDEF', 12)) 293 | return f'jdapp;iPhone;10.0.4;{iosVer};{uuid};network/wifi;ADID/{ADID};model/iPhone{iPhone},1;addressid/{addressid};appBuild/167707;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS {iosV} like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/null;supportJDSHWK/1' 294 | -------------------------------------------------------------------------------- /jbot/user/jupai.py: -------------------------------------------------------------------------------- 1 | from telethon import events 2 | import requests 3 | import urllib.parse 4 | from uuid import uuid4 5 | from .. import LOG_DIR 6 | 7 | try: 8 | from .login import user 9 | except: 10 | from .. import user 11 | 12 | @user.on(events.NewMessage(pattern=r'^jp', outgoing=True)) 13 | async def bot_bean(event): 14 | if event.is_reply is True: 15 | reply = await event.get_reply_message() 16 | text=reply.text 17 | else: 18 | msg_text= event.raw_text.split(' ') 19 | if isinstance(msg_text, list) and len(msg_text) == 2: 20 | text = msg_text[-1] 21 | else: 22 | text = None 23 | 24 | if text==None: 25 | await event.edit('格式:jp 内容') 26 | return 27 | else: 28 | await event.edit('开始生成图片,请稍后...') 29 | 30 | JP_IMG = f'{LOG_DIR}/bot/jp-{uuid4()}.png' 31 | params = { "msg": text } 32 | encoded = urllib.parse.urlencode(params) 33 | image_url = f"http://juapi.org/api/zt.php?{encoded}" 34 | response = requests.get(image_url) 35 | open(JP_IMG, "wb").write(response.content) 36 | await event.delete() 37 | await user.send_message(event.chat_id,file=JP_IMG) 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /jbot/user/jxjd_Global.py: -------------------------------------------------------------------------------- 1 | from telethon import events 2 | from .. import jdbot 3 | from ..diy.utils import read, write 4 | import re 5 | import requests,json 6 | 7 | try: 8 | from .login import user 9 | except: 10 | from .. import user 11 | 12 | @user.on(events.NewMessage(pattern=r'^jx', outgoing=True)) 13 | async def jcmd(event): 14 | strText="" 15 | if event.is_reply is True: 16 | reply = await event.get_reply_message() 17 | strText=reply.text 18 | else: 19 | msg_text= event.raw_text.split(' ') 20 | if isinstance(msg_text, list) and len(msg_text) == 2: 21 | strText = msg_text[-1] 22 | 23 | if strText==None: 24 | await user.send_message(event.chat_id,'请指定要解析的口令,格式: jx 口令 或对口令直接回复jx ') 25 | return 26 | 27 | jumpUrl="" 28 | title="" 29 | jiexiurl = "http://api.nolanstore.top/JComExchange" 30 | data ={"code": strText} 31 | headers={"Content-Type": "application/json"} 32 | issuccess=False 33 | for num in range(10): 34 | try: 35 | res=requests.post(url=jiexiurl,headers=headers,json=data,timeout=3) 36 | issuccess=True 37 | except: 38 | issuccess=False 39 | if issuccess: 40 | break 41 | resdata=json.loads(res.text) 42 | if resdata["code"]=="0": 43 | title = resdata["data"]['title'] 44 | jumpUrl = resdata["data"]['jumpUrl'] 45 | 46 | if jumpUrl != "": 47 | await user.send_message(event.chat_id,title+"\n"+jumpUrl) 48 | else: 49 | await user.send_message(event.chat_id,"解析出错:\n"+res.text) 50 | -------------------------------------------------------------------------------- /jbot/user/reply_msg.py: -------------------------------------------------------------------------------- 1 | from telethon import events 2 | 3 | from .login import user 4 | 5 | @user.on(events.NewMessage(pattern=r'^re[ 0-9]*$', outgoing=True)) 6 | async def mycp(event): 7 | num = event.raw_text.split(' ') 8 | if isinstance(num, list) and len(num) == 2: 9 | num = int(num[-1]) 10 | else: 11 | num = 1 12 | reply = await event.get_reply_message() 13 | await event.delete() 14 | for _ in range(0, num): 15 | await reply.forward_to(int(event.chat_id)) 16 | -------------------------------------------------------------------------------- /jbot/user/weather_Global.py: -------------------------------------------------------------------------------- 1 | from telethon import events 2 | import requests 3 | import json 4 | import os 5 | import asyncio 6 | try: 7 | from .login import user 8 | except: 9 | from .. import user 10 | 11 | @user.on(events.NewMessage(pattern=r'.*天气$', outgoing=True)) 12 | async def weatherInfo(event): 13 | 14 | #载入设定 15 | waitsec=0 16 | issetconfig=False 17 | 18 | if os.path.exists("/ql/data/config/auth.json"): 19 | configpath="/ql/data/" 20 | 21 | if os.path.exists("/ql/config/auth.json"): 22 | configpath="/ql/" 23 | 24 | if os.path.exists("/jd/config/config.sh"): 25 | configpath="/jd/" 26 | 27 | try: 28 | f = open(configpath+"config/ccbotSetting.json", "r+", encoding='utf-8') 29 | ccbotSetting = json.loads(f.read()) 30 | f.close() 31 | for key in ccbotSetting: 32 | if key=="天气命令配置": 33 | issetconfig=True 34 | except Exception as e: 35 | await event.edit(f'载入ccbotSetting.json出错,请检查内容!\n'+str(e)) 36 | return 37 | 38 | if not issetconfig: 39 | await event.edit(f'载入ccbotSetting.json成功,但是缺少相应的配置,请检查!') 40 | return 41 | 42 | try: 43 | for key in ccbotSetting["天气命令配置"]: 44 | if key=="多少秒后自动删除": 45 | waitsec=int(ccbotSetting["天气命令配置"][key]) 46 | except Exception as e: 47 | await event.edit(f'载入ccbotSetting.json的bd命令配置内容出错,请检查!\n'+str(e)) 48 | return 49 | 50 | message = event.message.text.split("天气")[0] 51 | if message==None: 52 | await event.edit('请输入正确的格式如:深圳天气') 53 | return 54 | 55 | url='http://hm.suol.cc/API/tq.php?msg='+message+'&n=1' 56 | try: 57 | weather_data=requests.get(url).text 58 | except Exception as e: 59 | await event.edit("获取天气信息错误:"+e) 60 | return 61 | strweatherinfo="" 62 | strotherinfo="" 63 | lncount=0 64 | weatherinfos=weather_data.split("\n") 65 | for weatherline in weatherinfos: 66 | lncount=lncount+1 67 | if ":" in weatherline: 68 | Title=weatherline.split(":")[0] 69 | if Title=="预警信息": 70 | strweatherinfo+=weatherline.replace("预警信息:","")+"\n" 71 | else: 72 | strweatherinfo+="【"+Title+"】 "+weatherline.split(":")[1]+"\n" 73 | else: 74 | if lncount==1: 75 | strweatherinfo+="【位置】 "+weatherline+"\n" 76 | else: 77 | if strotherinfo!="": 78 | strotherinfo+="\n" 79 | strotherinfo+=weatherline 80 | 81 | 82 | if strotherinfo!="": 83 | strweatherinfo+="【温馨提示】"+strotherinfo 84 | 85 | if strweatherinfo =="" : 86 | strweatherinfo='获取天气信息错误,可能输入的城市有误或不被支持!' 87 | 88 | if waitsec==0: 89 | await event.edit(strweatherinfo) 90 | else: 91 | strweatherinfo=strweatherinfo+"\n\n【本条信息将在"+str(waitsec)+"秒钟后自动删除】" 92 | await event.edit(strweatherinfo) 93 | await asyncio.sleep(waitsec) 94 | await event.delete() -------------------------------------------------------------------------------- /jbot/utils.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import importlib 3 | import os 4 | from . import logger 5 | 6 | 7 | def load_module(module, path): 8 | if module=='user': 9 | try: 10 | file="login.py" 11 | filename = file.replace('.py', '') 12 | name = "jbot.{}.{}".format(module, filename) 13 | spec = importlib.util.spec_from_file_location(name, path+file) 14 | load = importlib.util.module_from_spec(spec) 15 | spec.loader.exec_module(load) 16 | sys.modules[f"jbot.{module}.{filename}"] = load 17 | logger.info(f"Bot加载-->{filename}-->完成") 18 | except Exception as e: 19 | logger.info(f"Bot加载失败-->{file}-->{str(e)}") 20 | 21 | files = os.listdir(path) 22 | for file in files: 23 | if module=='user' and file=="login.py": 24 | continue 25 | 26 | try: 27 | if file.endswith('.py'): 28 | filename = file.replace('.py', '') 29 | name = "jbot.{}.{}".format(module, filename) 30 | spec = importlib.util.spec_from_file_location(name, path+file) 31 | load = importlib.util.module_from_spec(spec) 32 | spec.loader.exec_module(load) 33 | sys.modules[f"jbot.{module}.{filename}"] = load 34 | logger.info(f"Bot加载-->{filename}-->完成") 35 | except Exception as e: 36 | logger.info(f"Bot加载失败-->{file}-->{str(e)}") 37 | continue 38 | 39 | --------------------------------------------------------------------------------