├── .gitignore ├── .npmrc ├── package.json ├── README.md ├── Model ├── parser.js └── device.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | @icqqjs:registry=https://npm.pkg.github.com -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ICQQ-Plugin", 3 | "type": "module", 4 | "author": "TimeRainStarSky", 5 | "dependencies": { 6 | "icqq": "*" 7 | } 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # TRSS-Yunzai ICQQ Plugin 4 | 5 | TRSS-Yunzai ICQQ Bot 适配器 插件 6 | 7 | [![访问量](https://visitor-badge.glitch.me/badge?page_id=TimeRainStarSky.Yunzai-ICQQ-Plugin&right_color=red&left_text=访%20问%20量)](https://github.com/TimeRainStarSky/Yunzai-ICQQ-Plugin) 8 | [![Stars](https://img.shields.io/github/stars/TimeRainStarSky/Yunzai-ICQQ-Plugin?color=yellow&label=收藏)](../../stargazers) 9 | [![Downloads](https://img.shields.io/github/downloads/TimeRainStarSky/Yunzai-ICQQ-Plugin/total?color=blue&label=下载)](../../archive/main.tar.gz) 10 | [![Releases](https://img.shields.io/github/v/release/TimeRainStarSky/Yunzai-ICQQ-Plugin?color=green&label=发行版)](../../releases/latest) 11 | 12 | [![访问量](https://profile-counter.glitch.me/TimeRainStarSky-Yunzai-ICQQ-Plugin/count.svg)](https://github.com/TimeRainStarSky/Yunzai-ICQQ-Plugin) 13 | 14 |
15 | 16 | ## 安装教程 17 | 18 | 1. 准备:[TRSS-Yunzai](../../../Yunzai) 19 | 2. 输入:`#安装ICQQ-Plugin` 20 | 3. 输入:`#QQ签名[签名服务器地址]` 21 | 4. 输入:`#QQ设置QQ号:密码:登录设备` 22 | 23 | ## 安装 ICQQ 24 | 25 | ```sh 26 | cd plugins/ICQQ-Plugin 27 | 28 | pnpm login --scope=@icqqjs --auth-type=legacy --registry=https://npm.pkg.github.com 29 | 30 | UserName: # 你的 GitHub 账号 31 | Password: # 前往 https://github.com/settings/tokens/new 获取,scopes 勾选 read:packages 32 | E-Mail: # 你的公开邮箱地址 33 | 34 | pnpm add icqq@npm:@icqqjs/icqq 35 | ``` 36 | 37 | ## 格式示例 38 | 39 | - 密码登录:QQ号 `114514` 密码 `1919810` 登录设备 `安卓手机(1)/平板(2)` 40 | 41 | ``` 42 | #QQ设置114514:1919810:2 43 | ``` 44 | 45 | - 扫码登录:QQ号 `114514` 登录设备 `安卓手表(3)` 46 | 47 | ``` 48 | #QQ设置114514::3 49 | ``` 50 | 51 | ## 使用教程 52 | 53 | - #QQ账号 54 | - #QQ设置 + `QQ号:密码(留空扫码):登录设备:版本号:独立签名地址` 55 | - #QQ签名 + `签名服务器地址` -------------------------------------------------------------------------------- /Model/parser.js: -------------------------------------------------------------------------------- 1 | import zlib from"zlib";function parse(e,t){return new Parser(e,t)}class Parser{constructor(e,t){this.uin=t,this.message=[],this.brief="",this.content="",this.atme=!1,this.atall=!1,this.newImg=!1,this.imgprefix={},this.exclusive=!1;try{Array.isArray(e)?this.parseElems(e):(e[4]&&e[4].length&&this.parseExclusiveElem(0,e[4]),this.parseElems(Array.isArray(e[2])?e[2]:[e[2]]))}catch(e){console.error(e)}}getNextText(){try{var e=this.it?.next().value[1][1];return String(e[1])}catch{return"[未知]"}}parseExclusiveElem(e,t){let i,s;switch(e){case 12:case 51:var r=t[1].toBuffer();i={type:12===e?"xml":"json",data:String(0{var t,i=[];for(t of e=Array.isArray(e[1])?e[1]:[e[1]]){var s={id:"",render_data:{},action:{permission:{}}};t[1]&&(s.id=t[1]?.toString()),t[2]&&(s.render_data.label=t[2][1]?.toString(),s.render_data.visited_label=t[2][2]?.toString(),s.render_data.style=Number(t[2][3])||0),t[3]&&(s.action.type=Number(t[3][1])||0,s.action.unsupport_tips=t[3][4]?.toString(),s.action.data=t[3][5]?.toString(),s.action.reply=1===t[3][7],s.action.enter=1===t[3][8],t[3][2])&&(s.action.permission.type=Number(t[3][2][1])||0,s.action.permission.specify_role_ids=t[3][2][2]||[],s.action.permission.specify_user_ids=t[3][2][3]||[]),i.push(s)}return{buttons:i}})}},s="[button消息]",r=s}catch{return}break;case 48:switch(t[3]){case 10:case 20:if(!(i=this.parseNewImgElem(t[2],"image")))return;s=(i.asface?"[动画表情]":"[图片]")+(i.summary||""),r=`{image:${i.md5.toUpperCase()}}`;break;case 11:case 21:{let e=t[2][1];var n=(e=Array.isArray(e)?e:[e]).find(e=>100!==e[1][6]);i={type:"video",file:"protobuf://"+t.toBase64(),fid:n[1][2]?.toString(),md5:"ntvideo_"+n[1][1][2]?.toString(),size:n[1][1][1],seconds:n[1][1][8],nt:!0},s="视频",r=`{video:${i.fid}}`;break}case 12:case 22:n=t[2][1][1];i={type:"record",file:"protobuf://"+t.toBase64(),url:"",fid:n[2]?.toString(),md5:n[1][2]?.toString(),size:n[1][1],seconds:n[1][8],nt:!0},s="语音",r=`{ptt:${i.file}}`;break;default:return}break;default:return}2===this.message.length&&"at"===i.type&&"at"===this.message[0]?.type&&"text"===this.message[1]?.type&&this.message[0].qq===i.qq&&" "===this.message[1].text&&(this.message.splice(0,2),this.brief=""),this.brief+=s,this.content+=r,Array.isArray(this.message)||(this.message=[]);var l=this.message[this.message.length-1];"text"===i.type&&"text"===l?.type?l.text+=i.text:this.message.push(i)}parseElems(e){for(this.it=e.entries();;)try{var t=this.it.next().value?.[1];if(!t)break;var i=Number(Object.keys(Reflect.getPrototypeOf(t))[0]),s=t[i];if(16===i)this.extra=s;else if(21===i)this.anon=s;else if(45===i)this.quotation=s;else if(!this.exclusive)switch(i){case 1:case 2:case 4:case 6:case 8:case 31:case 34:case 37:this.parsePartialElem(i,s);break;case 5:case 12:case 19:case 51:this.parseExclusiveElem(i,s);break;case 53:3===s[1]?this.parseExclusiveElem(3,s[2][1]||s[2][2]):33===s[1]?this.parsePartialElem(33,s[2]):2===s[1]?this.parseExclusiveElem(126,s):37===s[1]?this.parseExclusiveElem(37,s):20===s[1]?this.parseExclusiveElem(51,s[2]):[45,46,48,500].includes(s[1])&&this.parsePartialElem(s[1],s)}}catch(e){console.error(e)}}parseNewImgElem(e,t){try{var i={type:t,file:e[1][1][1][4]?.toString(),url:"",fid:e[1][1][2]?.toString(),md5:e[1][1][1][2]?.toString(),height:e[1][1][1][7],width:e[1][1][1][6],size:e[1][1][1][1],summary:e[2][1]?.[2]?.toString(),nt:!0},s=("image"===t&&(i.asface=1===e[2][1]?.[1]),i.file=(0,this.image.buildImageFileParam)(i.md5,i.size,i.width,i.height,e[1][1][1][5][2]),((e[2][1]?.[11]||e[2][1]?.[12])?.[30]||"").toString());if(s?.length)return this.newImg=!0,i.url="https://"+e[1][2][3]+(s.startsWith("/")?s:""+e[1][2][1]+s)+(e[1][2][2][1]||"&spec=0"),i;i.md5&&(i.url="https://"+e[1][2][3]+e[1][2][1],this.imgprefix[i.md5]=i)}catch{if("flash"===t)return this.parseImgElem(0,e,t)}}parseImgElem(e,t,i){let s;var r,e="flash"===i?!!t[1]:8!==e,a=t[e?7:13].toHex(),c=(t[e?29:34]?.[30]||"").toString();return this.imgprefix[a]&&c?.length?(r=this.imgprefix[a].url?.length?new URL(this.imgprefix[a].url).origin:"",s={...this.imgprefix[a],type:i,url:`${c.startsWith("/")?""+r+c:""+this.imgprefix[a].url+c}&spec=0`}):((s={type:i,file:"",url:"",md5:a,height:t[e?8:23],width:t[e?9:22],size:t[e?2:25],summary:t[e?29:34]?.[e?8:9]?.toString()}).file=(0,this.image.buildImageFileParam)(s.md5,s.size,s.width,s.height,t[e?5:20]),"image"===i&&(s.asface=1===t[e?29:34]?.[1]),s.url||(c&&c.includes("fileid")?s.url=`https://c2cpicdw.qpic.cn${c}&spec=0`:t[16]&&String(t[16]).startsWith("/")?s.url="https://gchat.qpic.cn"+t[16]:t[15]&&String(t[15]).startsWith("/")?s.url="https://c2cpicdw.qpic.cn"+t[15]:s.url=`https://gchat.qpic.cn/gchatpic_new/0/0-0-${a.toUpperCase()}/0`),s)}}export{parse,Parser}; -------------------------------------------------------------------------------- /Model/device.js: -------------------------------------------------------------------------------- 1 | import fs from "fs";import path from"path";let mobile=[{name:"A9.2.27.636ed9e0",version:"9.2.27.31300",ver:"9.2.27",subid:537323303,apad_subid:537323342,qua:"V1_AND_SQ_9.2.27_12160_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2589",buildtime:1757058014,ssover:22,fekit_ver:"8.500.910"},{name:"A9.2.25.593ac7a8",version:"9.2.25.30450",ver:"9.2.25",subid:537318125,apad_subid:537318164,qua:"V1_AND_SQ_9.2.25_11820_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2589",buildtime:1757058014,ssover:22,fekit_ver:"8.500.910"},{name:"A9.2.20.777b5929",version:"9.2.20.30025",ver:"9.2.20",subid:537315786,apad_subid:537315825,qua:"V1_AND_SQ_9.2.20_11650_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2589",buildtime:1757058014,ssover:22,fekit_ver:"8.409.903"},{name:"A9.2.15.012a1717",version:"9.2.15.29600",ver:"9.2.15",subid:537312176,apad_subid:537312215,qua:"V1_AND_SQ_9.2.15_11480_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2588",buildtime:1755676630,ssover:22,fekit_ver:"8.408.897"},{name:"A9.2.10.fad8a0d9",version:"9.2.10.29175",ver:"9.2.10",subid:537309838,apad_subid:537309877,qua:"V1_AND_SQ_9.2.10_11310_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2587",buildtime:1754919788,ssover:22,fekit_ver:"8.407.888"},{name:"A9.2.5.2c3ad708",version:"9.2.5.28755",ver:"9.2.5",subid:537306612,apad_subid:537306651,qua:"V1_AND_SQ_9.2.5_11142_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2585",buildtime:1752744019,ssover:22,fekit_ver:"8.406.883"},{name:"A9.2.5.6039dd6b",version:"9.2.5.28750",ver:"9.2.5",subid:537306534,apad_subid:537306573,qua:"V1_AND_SQ_9.2.5_11140_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2585",buildtime:1752744019,ssover:22,fekit_ver:"8.406.883"},{name:"A9.2.0.0a244d9a",version:"9.2.0.28325",ver:"9.2.0",subid:537303052,apad_subid:537303091,qua:"V1_AND_SQ_9.2.0_10970_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2584",buildtime:1751448568,ssover:22,fekit_ver:"8.405.873"},{name:"A9.1.97.b351e214",version:"9.1.97.27900",ver:"9.1.97",subid:537301750,apad_subid:537301789,qua:"V1_AND_SQ_9.1.97_10800_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2582",buildtime:1748422598,ssover:22,fekit_ver:"8.404.864"},{name:"A9.1.95.1eed49c0",version:"9.1.95.27050",ver:"9.1.95",subid:537297272,apad_subid:537297311,qua:"V1_AND_SQ_9.1.95_10460_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2582",buildtime:1748422598,ssover:22,fekit_ver:"8.404.864"},{name:"A9.1.92.cb84b334",version:"9.1.92.26650",ver:"9.1.92",subid:537294996,apad_subid:537295035,qua:"V1_AND_SQ_9.1.92_10300_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2581",buildtime:1747820974,ssover:22,fekit_ver:"8.403.855"},{name:"A9.1.91.304e0cba",version:"9.1.91.26645",ver:"9.1.91",subid:537294918,apad_subid:537294957,qua:"V1_AND_SQ_9.1.91_10298_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2581",buildtime:1747820974,ssover:22,fekit_ver:"8.403.855"},{name:"A9.1.90.58326526",version:"9.1.90.26625",ver:"9.1.90",subid:537294606,apad_subid:537294645,qua:"V1_AND_SQ_9.1.90_10290_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2581",buildtime:1747820974,ssover:22,fekit_ver:"8.403.855"},{name:"A9.1.76.a36f04fb",version:"9.1.76.26090",ver:"9.1.76",subid:537288619,apad_subid:537288658,qua:"V1_AND_SQ_9.1.76_10076_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2578",buildtime:1746016194,ssover:22,fekit_ver:"8.402.848"},{name:"A9.1.75.ec478a78",version:"9.1.75.26070",ver:"9.1.75",subid:537288307,apad_subid:537288346,qua:"V1_AND_SQ_9.1.75_10068_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2578",buildtime:1746016194,ssover:22,fekit_ver:"8.402.840"},{name:"A9.1.71.7bacc589",version:"9.1.71.25665",ver:"9.1.71",subid:537286259,apad_subid:537286298,qua:"V1_AND_SQ_9.1.71_9906_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2574",buildtime:1745224715,ssover:22,fekit_ver:"8.401.830"},{name:"A9.1.70.88c475c0",version:"9.1.70.25645",ver:"9.1.70",subid:537285947,apad_subid:537285986,qua:"V1_AND_SQ_9.1.70_9898_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2574",buildtime:1745224715,ssover:22,fekit_ver:"8.401.830"},{name:"A9.1.67.06b27928",version:"9.1.67.25220",ver:"9.1.67",subid:537284101,apad_subid:537284140,qua:"V1_AND_SQ_9.1.67_9728_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2570",buildtime:1742975242,ssover:22,fekit_ver:"8.400.814"},{name:"A9.1.65.5017700a",version:"9.1.65.24795",ver:"9.1.65",subid:537278302,apad_subid:537278341,qua:"V1_AND_SQ_9.1.65_9558_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2570",buildtime:1742975242,bitmap:150470524,ssover:22,fekit_ver:"8.400.814"},{name:"A9.1.60.045f5d19",version:"9.1.60.24370",ver:"9.1.60",subid:537275636,apad_subid:537275675,qua:"V1_AND_SQ_9.1.60_9388_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2568",buildtime:1740483688,bitmap:150470524,ssover:22,fekit_ver:"8.400.807"},{name:"A9.1.55.464b50b2",version:"9.1.55.23945",ver:"9.1.55",subid:537272835,apad_subid:537272874,qua:"V1_AND_SQ_9.1.55_9218_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2568",buildtime:1740483688,bitmap:150470524,ssover:22,fekit_ver:"8.309.798"},{name:"A9.1.52.b97ab15e",version:"9.1.52.23535",ver:"9.1.52",subid:537270265,apad_subid:537270304,qua:"V1_AND_SQ_9.1.52_9054_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2566",buildtime:1737457591,bitmap:150470524,ssover:22,fekit_ver:"8.308.786"},{name:"A9.1.50.83cc325e",version:"9.1.50.23520",ver:"9.1.50",subid:537270031,apad_subid:537270070,qua:"V1_AND_SQ_9.1.50_9048_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2566",buildtime:1737457591,bitmap:150470524,ssover:22,fekit_ver:"8.308.786"},{name:"A9.1.35.9f1a1697",version:"9.1.35.22670",ver:"9.1.35",subid:537265576,apad_subid:537265615,qua:"V1_AND_SQ_9.1.35_8708_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.307.779"},{name:"A9.1.31.cb8cd007",version:"9.1.31.22255",ver:"9.1.31",subid:537262715,apad_subid:537262754,qua:"V1_AND_SQ_9.1.31_8542_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.306.776"},{name:"A9.1.30.a920c625",version:"9.1.30.22245",ver:"9.1.30",subid:537262559,apad_subid:537262598,qua:"V1_AND_SQ_9.1.30_8538_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.306.776"},{name:"A9.1.25.008c1bb3",version:"9.1.25.21820",ver:"9.1.25",subid:537260030,apad_subid:537260069,qua:"V1_AND_SQ_9.1.25_8368_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.305.770"},{name:"A9.1.20.fa404fa6",version:"9.1.20.21395",ver:"9.1.20",subid:537257414,apad_subid:537257453,qua:"V1_AND_SQ_9.1.20_8198_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.304.766"},{name:"A9.1.16.3fe73575",version:"9.1.16.20980",ver:"9.1.16",subid:537254305,apad_subid:537254344,qua:"V1_AND_SQ_9.1.16_8032_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.303.759"},{name:"A9.1.15.25851cef",version:"9.1.15.20970",ver:"9.1.15",subid:537254149,apad_subid:537254188,qua:"V1_AND_SQ_9.1.15_8028_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.303.755"},{name:"A9.1.10.2ce90365",version:"9.1.10.20545",ver:"9.1.10",subid:537251380,apad_subid:537251419,qua:"V1_AND_SQ_9.1.10_7858_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.302.739"},{name:"A9.1.5.468dd2ea",version:"9.1.5.20120",ver:"9.1.5",subid:537247779,apad_subid:537247818,qua:"V1_AND_SQ_9.1.5_7688_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2565",buildtime:1728390173,bitmap:150470524,ssover:22,fekit_ver:"8.301.724"},{name:"A9.1.0.2129b4e8",version:"9.1.0.19695",ver:"9.1.0",subid:537244893,apad_subid:537244932,qua:"V1_AND_SQ_9.1.0_7518_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2564",buildtime:1724730201,bitmap:150470524,ssover:22,fekit_ver:"8.209.692"},{name:"A9.0.95.705d26da",version:"9.0.95.19320",ver:"9.0.95",subid:537242075,apad_subid:537242114,qua:"V1_AND_SQ_9.0.95_7368_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2563",buildtime:1724313621,bitmap:150470524,ssover:22,fekit_ver:"8.208.645"},{name:"A9.0.90.38ae7504",version:"9.0.90.18945",ver:"9.0.90",subid:537239255,apad_subid:537239294,qua:"V1_AND_SQ_9.0.90_7218_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2561",buildtime:1718353600,bitmap:150470524,ssover:21,fekit_ver:"8.207.627"},{name:"A9.0.85.491c232e",version:"9.0.85.18570",ver:"9.0.85",subid:537236316,apad_subid:537236355,qua:"V1_AND_SQ_9.0.85_7068_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2561",buildtime:1718353600,bitmap:150470524,ssover:21,fekit_ver:"8.206.607"},{name:"A9.0.81.3daf0e38",version:"9.0.81.18205",ver:"9.0.81",subid:537233527,apad_subid:537233566,qua:"V1_AND_SQ_9.0.81_6922_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2561",buildtime:1718353600,bitmap:150470524,ssover:21,fekit_ver:"8.205.580"},{name:"A9.0.80.0d6f99ed",version:"9.0.80.18195",ver:"9.0.80",subid:537233371,apad_subid:537233410,qua:"V1_AND_SQ_9.0.80_6918_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2561",buildtime:1718353600,bitmap:150470524,ssover:21,fekit_ver:"8.205.580"},{name:"A9.0.75.c0dc0382",version:"9.0.75.17920",ver:"9.0.75",subid:537230737,apad_subid:537230776,qua:"V1_AND_SQ_9.0.75_6808_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2561",buildtime:1718353600,bitmap:150470524,ssover:21,fekit_ver:"8.204.574"},{name:"A9.0.71.e2f45246",version:"9.0.71.17655",ver:"9.0.71",subid:537228643,apad_subid:537228682,qua:"V1_AND_SQ_9.0.71_6702_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2561",buildtime:1718353600,bitmap:150470524,ssover:21,fekit_ver:"8.203.564"},{name:"A9.0.70.e4b76fcc",version:"9.0.70.17645",ver:"9.0.70",subid:537228487,apad_subid:537228526,qua:"V1_AND_SQ_9.0.70_6698_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2561",buildtime:1718353600,bitmap:150470524,ssover:21,fekit_ver:"8.203.564"},{name:"A9.0.65.530ce28d",version:"9.0.65.17370",ver:"9.0.65",subid:537225139,apad_subid:537225178,qua:"V1_AND_SQ_9.0.65_6588_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2560",buildtime:1713424357,bitmap:150470524,ssover:21,fekit_ver:"8.202.560"},{name:"A9.0.60.c5f71993",version:"9.0.60.17095",ver:"9.0.60",subid:537222797,apad_subid:537222836,qua:"V1_AND_SQ_9.0.60_6478_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2560",buildtime:1713424357,bitmap:150470524,ssover:21,fekit_ver:"8.201.556"},{name:"A9.0.56.c25547f8",version:"9.0.56.16830",ver:"9.0.56",subid:537220323,apad_subid:537220362,qua:"V1_AND_SQ_9.0.56_6372_YYB_D",sdkver:"6.0.0.2560",buildtime:1713424357,bitmap:150470524,ssover:21,fekit_ver:"8.200.555"},{name:"A9.0.55.54f52314",version:"9.0.55.16820",ver:"9.0.55",buildtime:1713424357,subid:537220167,apad_subid:537220206,bitmap:150470524,sdkver:"6.0.0.2560",qua:"V1_AND_SQ_9.0.55_6368_YYB_D",ssover:21,fekit_ver:"8.200.555"},{name:"A9.0.50.a9d8c8dc",version:"9.0.50.16545",ver:"9.0.50",buildtime:1710769234,subid:537217916,apad_subid:537217955,bitmap:150470524,sdkver:"6.0.0.2559",qua:"V1_AND_SQ_9.0.50_6258_YYB_D",ssover:21,fekit_ver:"8.106.542"},{name:"A9.0.35.52ab3f26",version:"9.0.35.16275",ver:"9.0.35",buildtime:1710769234,subid:537215475,apad_subid:537215514,bitmap:150470524,sdkver:"6.0.0.2559",qua:"V1_AND_SQ_9.0.35_6150_YYB_D",ssover:21,fekit_ver:"8.105.541"},{name:"A9.0.35.50c16765",version:"9.0.35.16270",ver:"9.0.35",buildtime:1710769234,subid:537215397,apad_subid:537215436,bitmap:150470524,sdkver:"6.0.0.2559",qua:"V1_AND_SQ_9.0.35_6148_YYB_D",ssover:21,fekit_ver:"8.105.541"},{name:"A9.0.30.47d3bd6c",version:"9.0.30.15995",ver:"9.0.30",buildtime:1710769234,subid:537211926,apad_subid:537211965,bitmap:150470524,sdkver:"6.0.0.2559",qua:"V1_AND_SQ_9.0.30_6038_YYB_D",ssover:21,fekit_ver:"8.104.509"},{name:"A9.0.25.63b29b33",version:"9.0.25.15760",ver:"9.0.25",buildtime:1702888273,subid:537210084,apad_subid:537210123,bitmap:150470524,sdkver:"6.0.0.2558",qua:"V1_AND_SQ_9.0.25_5942_YYB_D",ssover:21,fekit_ver:"8.103.508"},{name:"A9.0.25.e1f154c9",version:"9.0.25.15735",ver:"9.0.25",buildtime:1702888273,subid:537210006,apad_subid:537210045,bitmap:150470524,sdkver:"6.0.0.2558",qua:"V1_AND_SQ_9.0.25_5932_YYB_D",ssover:21,fekit_ver:"8.103.508"},{name:"A9.0.20.38faf5bf",version:"9.0.20.15515",ver:"9.0.20",buildtime:1702888273,subid:537206436,apad_subid:537206475,bitmap:150470524,sdkver:"6.0.0.2558",qua:"V1_AND_SQ_9.0.20_5844_YYB_D",ssover:21,fekit_ver:"8.102.502"},{name:"A9.0.17.215f2081",version:"9.0.17.15190",ver:"9.0.17",subid:537204134,apad_subid:537204173,qua:"V1_AND_SQ_9.0.17_5714_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2558",buildtime:1702888273,ssover:21,fekit_ver:"8.101.471"},{name:"A9.0.17.6a4a36ca",version:"9.0.17.15185",ver:"9.0.17",buildtime:1702888273,subid:537204056,apad_subid:537204095,bitmap:150470524,sdkver:"6.0.0.2558",qua:"V1_AND_SQ_9.0.17_5712_YYB_D",ssover:21,fekit_ver:"8.101.471"},{name:"A9.0.15.4145f774",version:"9.0.15.14970",ver:"9.0.15",subid:537202216,apad_subid:537202255,qua:"V1_AND_SQ_9.0.15_5626_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2558",buildtime:1702888273,ssover:21,fekit_ver:"8.101.471"},{name:"A9.0.8.10368491",version:"9.0.8.14755",ver:"9.0.8",subid:537200218,apad_subid:537200257,qua:"V1_AND_SQ_9.0.8_5540_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2558",buildtime:1702888273,ssover:21,fekit_ver:"8.100.460"},{name:"A9.0.0.0ebb1ecb",version:"9.0.0.14110",ver:"9.0.0",buildtime:1701164403,subid:537194351,apad_subid:537194390,bitmap:150470524,sdkver:"6.0.0.2557",qua:"V1_AND_SQ_9.0.0_5282_YYB_D",ssover:21,fekit_ver:"8.0.456"},{name:"A8.9.93.bf80f08f",version:"8.9.93.13475",ver:"8.9.93",buildtime:1697015435,subid:537187398,apad_subid:537187437,bitmap:150470524,sdkver:"6.0.0.2556",qua:"V1_AND_SQ_8.9.93_5028_YYB_D",ssover:21,fekit_ver:"7.301.417"},{name:"A8.9.90.cccfa0d0",version:"8.9.90.13250",ver:"8.9.90",buildtime:1697015435,subid:537185007,apad_subid:537185046,bitmap:150470524,sdkver:"6.0.0.2556",qua:"V1_AND_SQ_8.9.90_4938_YYB_D",ssover:21,fekit_ver:"7.301.417"},{name:"A8.9.88.46a07457",version:"8.9.88.13035",ver:"8.9.88",buildtime:1697015435,subid:537182769,apad_subid:537182808,bitmap:150470524,sdkver:"6.0.0.2556",qua:"V1_AND_SQ_8.9.88_4852_YYB_D",ssover:21,fekit_ver:"7.300.410"},{name:"A8.9.85.3377f9bf",version:"8.9.85.12820",ver:"8.9.85",buildtime:1697015435,subid:537180568,apad_subid:537180607,bitmap:150470524,sdkver:"6.0.0.2556",qua:"V1_AND_SQ_8.9.85_4766_YYB_D",ssover:21,fekit_ver:"7.103.403"},{name:"A8.9.83.c9a61e5e",version:"8.9.83.12605",ver:"8.9.83",buildtime:1691565978,subid:537178646,apad_subid:537178685,bitmap:150470524,sdkver:"6.0.0.2554",qua:"V1_AND_SQ_8.9.83_4680_YYB_D",ssover:20,fekit_ver:"7.102.401"},{name:"A8.9.80.57a42f50",version:"8.9.80.12440",ver:"8.9.80",buildtime:1691565978,subid:537176863,apad_subid:537176902,bitmap:150470524,sdkver:"6.0.0.2554",qua:"V1_AND_SQ_8.9.80_4614_YYB_D",ssover:20,fekit_ver:"7.101.381"},{name:"A8.9.78.d5d9d71d",version:"8.9.78.12275",ver:"8.9.78",buildtime:1691565978,subid:537175315,apad_subid:537175354,bitmap:150470524,sdkver:"6.0.0.2554",qua:"V1_AND_SQ_8.9.78_4548_YYB_D",ssover:20,fekit_ver:"7.100.363"},{name:"A8.9.76.cefd59d7",version:"8.9.76.12115",ver:"8.9.76",subid:537173573,apad_subid:537173621,qua:"V1_AND_SQ_8.9.76_4484_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2554",buildtime:1691565978,ssover:20,fekit_ver:"7.0.344"},{name:"A8.9.76.c71a1fa8",version:"8.9.76.12115",ver:"8.9.76",buildtime:1691565978,subid:537173477,apad_subid:537173525,bitmap:150470524,sdkver:"6.0.0.2554",qua:"V1_AND_SQ_8.9.76_4484_YYB_D",ssover:20,fekit_ver:"7.0.344"},{name:"A8.9.75.354d41fc",version:"8.9.75.12110",ver:"8.9.75",buildtime:1691565978,subid:537173381,apad_subid:537173429,bitmap:150470524,sdkver:"6.0.0.2554",qua:"V1_AND_SQ_8.9.75_4482_YYB_D",ssover:20,fekit_ver:"7.0.344"},{name:"A8.9.73.08fbad4d",version:"8.9.73.11950",ver:"8.9.73",subid:537171785,apad_subid:537171833,qua:"V1_AND_SQ_8.9.73_4416_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2553",buildtime:1690371091,ssover:20,fekit_ver:"7.0.337"},{name:"A8.9.73.5b437a51",version:"8.9.73.11945",ver:"8.9.73",subid:537171689,apad_subid:537171737,qua:"V1_AND_SQ_8.9.73_4416_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2553",buildtime:1690371091,ssover:20,fekit_ver:"7.0.337"},{name:"A8.9.71.9fd08ae5",version:"8.9.71.11735",ver:"8.9.71",subid:537170024,apad_subid:537170072,qua:"V1_AND_SQ_8.9.71_4332_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2551",buildtime:1688720082,ssover:20,fekit_ver:"7.0.326"},{name:"A8.9.70.b4332bd3",version:"8.9.70.11730",ver:"8.9.70",subid:537169928,apad_subid:537169976,qua:"V1_AND_SQ_8.9.70_4330_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2551",buildtime:1688720082,ssover:20,fekit_ver:"7.0.326"},{name:"A8.9.68.e757227e",version:"8.9.68.11565",ver:"8.9.68",subid:537168313,apad_subid:537168361,qua:"V1_AND_SQ_8.9.68_4264_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2549",buildtime:1687254022,ssover:20,fekit_ver:"7.0.300"},{name:"A8.9.63.5156de84",version:"8.9.63.11390",ver:"8.9.63",subid:537164840,apad_subid:537164888,qua:"V1_AND_SQ_8.9.63_4194_YYB_D",channel:"GuanWang",sdkver:"6.0.0.2546",buildtime:1685069178,ssover:20,fekit_ver:"6.100.248"}].map(e=>({id:"com.tencent.mobileqq",nt:!0,appid:16,app_key:"0S200MNJT807V3GE",sign:Buffer.from("A6 B7 45 BF 24 A2 C2 77 52 77 16 F6 F3 6E B6 8D".split(" ").map(e=>parseInt(e,16))),main_sig_map:16724722,sub_sig_map:66560,display:"Android",device_type:-1,bitmap:150470524,...e})),tim=[{nt:!0,name:"A4.1.0.e4e0ee28",version:"4.1.0.4050",ver:"4.1.0",subid:537298353,apad_subid:537298411,qua:"V1_AND_SQ_9.0.95_4050_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2563",buildtime:1724313621,ssover:22,fekit_ver:"8.402.854"},{nt:!0,name:"A4.0.99.dc92ee7f",version:"4.0.99.4030",ver:"4.0.99",subid:537282136,apad_subid:537282194,qua:"V1_AND_SQ_9.0.95_4030_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2563",buildtime:1724313621,bitmap:150470524,ssover:22,fekit_ver:"8.301.736"},{nt:!0,name:"A4.0.98.2e3d9799",version:"4.0.98.4012",ver:"4.0.98",subid:537264175,apad_subid:537264222,qua:"V1_AND_SQ_9.0.95_4012_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2563",buildtime:1724313621,bitmap:150470524,ssover:22,fekit_ver:"8.301.736"},{nt:!0,name:"A4.0.97.3110ef2b",version:"4.0.97.4011",ver:"4.0.97",subid:537263469,apad_subid:537263596,qua:"V1_AND_SQ_9.0.95_4011_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2563",buildtime:1724313621,bitmap:150470524,ssover:22,fekit_ver:"8.301.736"},{nt:!0,name:"A4.0.96.6c784d54",version:"4.0.96.4010",ver:"4.0.96",subid:537261131,apad_subid:537261188,qua:"V1_AND_SQ_9.0.95_4010_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2563",buildtime:1724313621,bitmap:150470524,ssover:22,fekit_ver:"8.301.736"},{nt:!0,name:"A4.0.95.3b8db658",version:"4.0.95.4008",ver:"4.0.95",subid:537249218,apad_subid:537249147,qua:"V1_AND_SQ_9.0.95_4008_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2563",buildtime:1724313621,bitmap:150470524,ssover:22,fekit_ver:"8.301.736"},{name:"A3.5.8.0b4a96f9",version:"3.5.8.3228",ver:"3.5.8",subid:537237656,qua:"V1_AND_SQ_8.3.9_358_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2484",buildtime:1630062176,ssover:18,fekit_ver:"8.200.582"},{name:"A3.5.7.877bb8bb",version:"3.5.7.3218",ver:"3.5.7",buildtime:1630062176,subid:537223825,bitmap:150470524,sdkver:"6.0.0.2484",qua:"V1_AND_SQ_8.3.9_357_TIM_D",ssover:18,fekit_ver:"8.200.552"},{name:"A3.5.6.20c82aa0",version:"3.5.6.3208",ver:"3.5.6",buildtime:1630062176,subid:537181169,bitmap:150470524,sdkver:"6.0.0.2484",qua:"V1_AND_SQ_8.3.9_356_TIM_D",ssover:18,fekit_ver:"7.101.411"},{name:"A3.5.5.fa2ef27c",version:"3.5.5.3198",ver:"3.5.5",buildtime:1630062176,subid:537177451,bitmap:150470524,sdkver:"6.0.0.2484",qua:"V1_AND_SQ_8.3.9_355_TIM_D",ssover:18,fekit_ver:"7.100.363"},{name:"A3.5.2.3f4af297",version:"3.5.2.3178",ver:"3.5.2",buildtime:1630062176,subid:537162286,bitmap:150470524,sdkver:"6.0.0.2484",qua:"V1_AND_SQ_8.3.9_352_TIM_D",ssover:18,fekit_ver:"0"},{name:"A3.5.1.db08e878",version:"3.5.1.3168",ver:"3.5.1",buildtime:1630062176,subid:537150355,bitmap:150470524,sdkver:"6.0.0.2484",qua:"V1_AND_SQ_8.3.9_351_TIM_D",ssover:18,fekit_ver:"0"},{name:"A3.5.0.88ad9c55",version:"3.5.0.3148",ver:"3.5.0",buildtime:1630062176,subid:537143920,qua:"V1_AND_SQ_8.3.9_350_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2484",ssover:18,fekit_ver:"0"},{name:"A3.5.0.fda8b509",version:"3.5.0.3138",ver:"3.5.0",buildtime:1630062176,subid:537142492,qua:"V1_AND_SQ_8.3.9_350_TIM_D",channel:"GuanWang",sdkver:"6.0.0.2484",ssover:18,fekit_ver:"0"}].map(e=>({id:"com.tencent.tim",app_key:"0S200MNJT807V3GE",sign:Buffer.from("775e696d09856872fdd8ab4f3f06b1e0","hex"),appid:16,main_sig_map:16724722,sub_sig_map:66560,display:"Tim",device_type:-1,bitmap:150470524,...e})),watch=[{name:"Atestrevision",version:"2.0.8",ver:"2.0.8",buildtime:1559564731,subid:537065138,bitmap:16252796,sdkver:"6.0.0.2365",qua:"",ssover:5},{name:"Atestrevision",version:"9.0.7.2561",ver:"9.0.7",subid:537282233,channel:"",sdkver:"6.0.0.2564",qua:"V1_WAT_SQ_9.0.7_0_IDC_B",buildtime:1724730201,ssover:22,fekit_ver:"8.403.543"},{name:"Atestrevision",version:"9.0.5.2533",ver:"9.0.5",subid:537258298,channel:"",sdkver:"6.0.0.2564",qua:"V1_WAT_SQ_9.0.3_0_IDC_B",buildtime:1724730201,ssover:22,fekit_ver:"8.208.537"},{name:"Atestrevision",version:"9.0.3.2508",ver:"9.0.3",subid:537243416,channel:"",sdkver:"6.0.0.2498",qua:"V1_WAT_SQ_9.0.3_0_IDC_B",buildtime:1648001696,ssover:18,fekit_ver:"8.105.526"},{name:"Atestrevision",version:"9.0.1.2451",ver:"9.0.1",subid:537214131,channel:"",sdkver:"6.0.0.2498",qua:"V1_AND_SQ_8.9.68_0_RDM_B",buildtime:1648001696,ssover:18,fekit_ver:"8.105.526"},{name:"Atestrevision",version:"2.1.7",ver:"2.1.7",buildtime:1654570540,subid:537140974,bitmap:16252796,sdkver:"6.0.0.2366",qua:"V1_WAT_SQ_2.1.7_002_IDC_B",ssover:5,fekit_ver:"0"}].map(e=>({id:"com.tencent.qqlite",app_key:"0S200MNJT807V3GE",sign:Buffer.from("A6 B7 45 BF 24 A2 C2 77 52 77 16 F6 F3 6E B6 8D".split(" ").map(e=>parseInt(e,16))),appid:16,main_sig_map:16724722,sub_sig_map:66560,display:"Watch",device_type:8,bitmap:150470524,...e})),hd={id:"com.tencent.qq",app_key:"0S200MNJT807V3GE",name:"A6.8.2.21241",version:"6.8.2.21241",ver:"6.8.2",sign:mobile[0].sign,buildtime:1647227495,appid:16,subid:537128930,bitmap:150470524,main_sig_map:1970400,sub_sig_map:66560,sdkver:"6.2.0.1023",display:"iMac",device_type:5,qua:"",ssover:12},apklist={[1]:mobile,2:mobile.map(e=>({...e,subid:e?.apad_subid||e.subid,display:e?.apad_subid?"aPad":e.display})),3:watch,4:{...hd},5:{...mobile[0],id:"com.tencent.mqq",subid:537155074,sign:hd.sign,name:"8.9.50.611",version:"8.9.50.611",ver:"8.9.50",sdkver:"6.0.0.2535",qua:"",display:"iPad",ssover:19},6:tim,7:[]};function readCustomApkInfoList(){let e="data/icqq/custom-apks.json";try{var _;return fs.existsSync(e)?(_=JSON.parse(fs.readFileSync(e).toString()),(Array.isArray(_)?_:_?[_]:[]).map(e=>(e.sign=Buffer.from(e.sign,"hex"),{...mobile[0],nt:!1,qr_appid:0,fekit_ver:void 0,...e}))):(fs.existsSync(path.dirname(e))||fs.mkdirSync(path.dirname(e),{recursive:!0}),fs.writeFileSync(e,JSON.stringify([mobile[0]].map(e=>(delete(e={...e}).apad_subid,e.sign=e.sign.toString("hex"),e)),null,1)),Bot.makeLog("mark","创建了自定义版本信息文件:"+e),[mobile[0]])}catch(e){return console.log(e),[]}}export function getApkInfoList(e){7===e&&(apklist[e]=readCustomApkInfoList());e=Array.isArray(apklist[e])?apklist[e]:apklist[e]?[apklist[e]]:[];if(e.length)return e;throw new Error("版本列表为空")} -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | logger.info(logger.yellow("- 正在加载 ICQQ 适配器插件")) 2 | 3 | import makeConfig from "../../lib/plugins/config.js" 4 | import cfg from "../../lib/config/config.js" 5 | import { ulid } from "ulid" 6 | 7 | import url from "url" 8 | import path from "path" 9 | import fs from "node:fs/promises" 10 | 11 | const __filename = url.fileURLToPath(import.meta.url) 12 | const __dirname = path.dirname(__filename) 13 | 14 | let icqq 15 | for (const i of ["Model", "node_modules"]) 16 | try { 17 | const dir = `${__dirname}/${i}/icqq/` 18 | if (!(await fs.stat(dir))) continue 19 | const p = JSON.parse(await fs.readFile(`${dir}package.json`, "utf8")) 20 | icqq = (await import(`file://${dir}${p.main}`)).default 21 | icqq.package = p 22 | if (!p.version.startsWith("0")) break 23 | ;(await import(`file://${dir}lib/core/device.js`)).default.getApkInfoList = ( 24 | await import("./Model/device.js") 25 | ).getApkInfoList 26 | Object.assign( 27 | (await import(`file://${dir}lib/message/parser.js`)).default, 28 | await import("./Model/parser.js"), 29 | ) 30 | Object.assign(icqq.Parser.prototype, { 31 | core: icqq.core, 32 | face: await import(`file://${dir}lib/message/face.js`), 33 | image: await import(`file://${dir}lib/message/image.js`), 34 | }) 35 | break 36 | } catch (err) { 37 | icqq = err 38 | } 39 | 40 | if (icqq instanceof Error) throw icqq 41 | 42 | const { config, configSave } = await makeConfig( 43 | "ICQQ", 44 | { 45 | tips: "", 46 | permission: "master", 47 | markdown: { 48 | mode: false, 49 | button: false, 50 | callback: true, 51 | }, 52 | bot: {}, 53 | token: [], 54 | }, 55 | { 56 | tips: [ 57 | "欢迎使用 TRSS-Yunzai ICQQ Plugin ! 作者:时雨🌌星空", 58 | "参考:https://github.com/TimeRainStarSky/Yunzai-ICQQ-Plugin", 59 | ], 60 | }, 61 | ) 62 | 63 | const adapter = new (class ICQQAdapter { 64 | constructor() { 65 | this.id = "QQ" 66 | this.name = "ICQQ" 67 | this.version = `v${icqq.package.version}` 68 | } 69 | 70 | async uploadVideo(id, file) { 71 | const group = Bot[id].pickGroup(Math.ceil(Math.random() * 10 ** 9)) 72 | const video = await group.uploadVideo({ file }) 73 | const proto = Bot[id].icqq.core.pb.decode( 74 | Buffer.from(video.file.replace("protobuf://", ""), "base64"), 75 | ) 76 | return group.getVideoUrl(proto[1], proto[2]) 77 | } 78 | 79 | async uploadRecord(id, file) { 80 | const group = Bot[id].pickGroup(Math.ceil(Math.random() * 10 ** 9)) 81 | const record = await group.uploadPtt({ file }) 82 | const proto = Bot[id].icqq.core.pb.decode( 83 | Buffer.from(record.file.replace("protobuf://", ""), "base64"), 84 | ) 85 | const body = Bot[id].icqq.core.pb.encode({ 86 | 1: 1200, 87 | 2: 0, 88 | 14: { 10: id, 20: proto[3], 30: 2 }, 89 | 101: 17, 90 | 102: 104, 91 | 99999: { 90300: 1, 91000: 2, 91100: 1 }, 92 | }) 93 | const payload = await Bot[id].sendUni( 94 | "PttCenterSvr.pb_pttCenter_CMD_REQ_APPLY_DOWNLOAD-1200", 95 | body, 96 | ) 97 | const rsp = Bot[id].icqq.core.pb.decode(payload)[14] 98 | if (rsp[10] !== 0) Bot.makeLog("error", [rsp, "获取语音下载地址失败"], id) 99 | const url = new URL(String(rsp[30][50])) 100 | url.host = "grouptalk.c2c.qq.com" 101 | url.protocol = "https" 102 | return url.href 103 | } 104 | 105 | async uploadImage(id, file) { 106 | const image = new Bot[id].icqq.Image({ file }) 107 | image.upload = await Bot[id].pickGroup(Math.ceil(Math.random() * 10 ** 9)).uploadImages([image]) 108 | if (image.upload[0].status === "fulfilled") 109 | image.url = Bot[id].icqq.getGroupImageUrl(image.md5.toString("hex")) 110 | return image 111 | } 112 | 113 | async makeMarkdownImage(id, file) { 114 | const image = await Bot[id].uploadImage(file) 115 | return { 116 | des: `![图片 #${image.width || 0}px #${image.height || 0}px]`, 117 | url: `(${image.url})`, 118 | } 119 | } 120 | 121 | makeMarkdownText(text) { 122 | const match = text.match( 123 | /https?:\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/g, 124 | ) 125 | if (match) for (const url of match) text = text.replace(url, `<${url}>`) 126 | return text 127 | } 128 | 129 | makeButton(id, pick, button, style, forward) { 130 | const msg = { 131 | id: ulid(), 132 | render_data: { 133 | label: button.text, 134 | visited_label: button.clicked_text, 135 | style, 136 | ...button.QQBot?.render_data, 137 | }, 138 | } 139 | 140 | if (button.link) 141 | msg.action = { 142 | type: 0, 143 | permission: { type: 2 }, 144 | data: button.link, 145 | ...button.QQBot?.action, 146 | } 147 | else if (button.input) 148 | msg.action = { 149 | type: 2, 150 | permission: { type: 2 }, 151 | data: button.input, 152 | enter: button.send, 153 | ...button.QQBot?.action, 154 | } 155 | else if (button.callback) 156 | msg.action = { 157 | type: 2, 158 | permission: { type: 2 }, 159 | data: button.callback, 160 | enter: true, 161 | ...button.QQBot?.action, 162 | } 163 | else return false 164 | 165 | if (forward && config.markdown.callback && (button.input || button.callback)) 166 | for (const i of Bot.uin) 167 | if (Bot[i].adapter?.id === "QQBot" && Bot[i].sdk?.config?.appid && Bot[i].callback) { 168 | msg.action.type = 1 169 | delete msg.action.data 170 | this.markdown_appid = Number(Bot[i].sdk.config.appid) 171 | Bot[i].callback[msg.id] = { 172 | self_id: id, 173 | user_id: pick.user_id, 174 | group_id: pick.group_id, 175 | message: button.input || button.callback, 176 | } 177 | setTimeout(() => delete Bot[i].callback[msg.id], 3600000) 178 | break 179 | } 180 | 181 | if (button.permission) { 182 | if (button.permission === "admin") { 183 | msg.action.permission.type = 1 184 | } else { 185 | msg.action.permission.type = 0 186 | msg.action.permission.specify_user_ids = String(button.permission) 187 | } 188 | } 189 | return msg 190 | } 191 | 192 | makeButtons(id, pick, button_square, forward) { 193 | const msgs = [] 194 | const random = Math.floor(Math.random() * 2) 195 | for (const button_row of button_square) { 196 | let column = 0 197 | const buttons = [] 198 | for (let button of button_row) { 199 | button = this.makeButton( 200 | id, 201 | pick, 202 | button, 203 | (random + msgs.length + buttons.length) % 2, 204 | forward, 205 | ) 206 | if (button) buttons.push(button) 207 | } 208 | if (buttons.length) msgs.push({ buttons }) 209 | } 210 | return msgs 211 | } 212 | 213 | async makeMarkdownMsg(id, pick, msg) { 214 | const messages = [] 215 | let content = "" 216 | const button = [] 217 | const forward = [] 218 | 219 | for (let i of Array.isArray(msg) ? msg : [msg]) { 220 | if (typeof i === "object") i = { ...i } 221 | else i = { type: "text", text: i } 222 | 223 | switch (i.type) { 224 | case "text": 225 | content += this.makeMarkdownText(i.text) 226 | break 227 | case "image": { 228 | const { des, url } = await this.makeMarkdownImage(id, i.file) 229 | content += `${des}${url}` 230 | break 231 | } 232 | case "file": 233 | if (i.file) i.file = await Bot.fileToUrl(i.file, i) 234 | content += this.makeMarkdownText(`文件:${i.file}`) 235 | break 236 | case "at": 237 | if (i.qq === "all") { 238 | content += "[@全体成员](mqqapi://markdown/mention?at_type=everyone)" 239 | } else { 240 | if (!i.name) { 241 | let info 242 | if (pick.pickMember) info = pick.pickMember(i.qq).info 243 | info ??= 244 | Bot[id].pickFriend(i.qq).info || (await Bot[id].pickUser(i.qq).getSimpleInfo()) 245 | if (info) i.name = info.card || info.nickname 246 | } 247 | 248 | if (i.name) i.name += `(${i.qq})` 249 | else i.name = i.qq 250 | content += `[@${i.name}](mqqapi://markdown/mention?at_type=1&at_tinyid=${i.qq})` 251 | } 252 | break 253 | case "markdown": 254 | content += i.data 255 | break 256 | case "button": 257 | button.push(...this.makeButtons(id, pick, i.data, true)) 258 | break 259 | case "node": 260 | for (const node of i.data) 261 | for (const message of await this.makeMarkdownMsg(id, pick, node.message)) 262 | forward.push({ user_id: 80000000, nickname: "匿名消息", ...node, ...message }) 263 | break 264 | case "raw": 265 | messages.push([icqq.Converter.prototype.hasOwnProperty(i.data?.type) ? i.data : i]) 266 | break 267 | default: 268 | if (icqq.Converter.prototype.hasOwnProperty(i.type)) { 269 | messages.push([i]) 270 | continue 271 | } 272 | content += this.makeMarkdownText(Bot.String(i)) 273 | } 274 | } 275 | 276 | if (content) messages.unshift([{ type: "markdown", content }]) 277 | if (button.length) { 278 | for (const i of messages) { 279 | if (i[0].type === "markdown") 280 | i.push({ 281 | type: "button", 282 | content: { 283 | appid: this.markdown_appid, 284 | rows: button.splice(0, 5), 285 | }, 286 | }) 287 | if (!button.length) break 288 | } 289 | while (button.length) 290 | messages.push([ 291 | { type: "markdown", content: " " }, 292 | { 293 | type: "button", 294 | content: { 295 | appid: this.markdown_appid, 296 | rows: button.splice(0, 5), 297 | }, 298 | }, 299 | ]) 300 | } 301 | 302 | for (const i of messages) forward.push({ type: "node", message: i }) 303 | return forward 304 | } 305 | 306 | async makeMsg(id, pick, msg) { 307 | if (!Array.isArray(msg)) msg = [msg] 308 | const message = [] 309 | const messages = [] 310 | const forward = [] 311 | let reply 312 | 313 | for (let i of msg) { 314 | if (typeof i === "object") 315 | switch (i.type) { 316 | case "text": 317 | case "image": 318 | case "face": 319 | break 320 | case "file": 321 | await pick.sendFile(i.file, i.name) 322 | continue 323 | case "reply": 324 | reply = i 325 | continue 326 | case "at": 327 | if (i.qq !== "all" && !i.name) { 328 | let info 329 | if (pick.pickMember) info = pick.pickMember(i.qq).info 330 | else info = Bot[id].pickFriend(i.qq).info 331 | if (!info) info = await Bot[id].pickUser(i.qq).getSimpleInfo() 332 | if (info) i.name = info.card || info.nickname 333 | } 334 | if (i.name && !i.text) i.text = `${i.name}(${i.qq})` 335 | break 336 | case "markdown": 337 | forward.push(...(await this.makeMarkdownMsg(id, pick, msg))) 338 | continue 339 | case "button": 340 | if (config.markdown.button) { 341 | if (config.markdown.button === "direct" || config.markdown.mode === "mix") 342 | message.push({ 343 | type: "button", 344 | appid: this.markdown_appid, 345 | content: { rows: this.makeButtons(id, pick, i.data) }, 346 | }) 347 | else if (config.markdown.button === "separate") 348 | messages.push([ 349 | { 350 | type: "button", 351 | appid: this.markdown_appid, 352 | content: { rows: this.makeButtons(id, pick, i.data) }, 353 | }, 354 | ]) 355 | else return [await this.makeMarkdownMsg(id, pick, msg)] 356 | } 357 | continue 358 | case "node": 359 | for (const node of i.data) 360 | for (const message of await this.makeMsg(id, pick, node.message)) 361 | forward.push({ 362 | user_id: 80000000, 363 | nickname: "匿名消息", 364 | ...node, 365 | type: "node", 366 | message, 367 | }) 368 | continue 369 | case "raw": 370 | if (icqq.Converter.prototype.hasOwnProperty(i.data?.type)) i = i.data 371 | break 372 | case "long_msg": 373 | if (msg.length > 1) continue 374 | break 375 | default: 376 | if (icqq.Converter.prototype.hasOwnProperty(i.type)) { 377 | messages.push([i]) 378 | continue 379 | } 380 | i = Bot.String(i) 381 | } 382 | message.push(i) 383 | } 384 | 385 | if (message.length) messages.push(message) 386 | if (forward.length) messages.push(forward) 387 | if (reply) for (const i of messages) i.unshift(reply) 388 | return messages 389 | } 390 | 391 | async sendMsg(id, pick, msg, ...args) { 392 | const rets = { message_id: [], data: [], error: [] } 393 | let msgs 394 | 395 | const sendMsg = async () => { 396 | for (const i of msgs) 397 | try { 398 | Bot.makeLog("debug", ["发送消息", i], id) 399 | const ret = await pick.sendMsg(i, ...args) 400 | Bot.makeLog("debug", ["发送消息返回", ret], id) 401 | 402 | rets.data.push(ret) 403 | if (ret.message_id) rets.message_id.push(ret.message_id) 404 | } catch (err) { 405 | Bot.makeLog("error", ["发送消息错误", i, err], id) 406 | rets.error.push(err) 407 | return false 408 | } 409 | } 410 | 411 | if (config.markdown.mode) { 412 | if (config.markdown.mode === "mix") 413 | msgs = [...(await this.makeMsg(id, pick, msg)), await this.makeMarkdownMsg(id, pick, msg)] 414 | else msgs = [await this.makeMarkdownMsg(id, pick, msg)] 415 | } else { 416 | msgs = await this.makeMsg(id, pick, msg) 417 | } 418 | 419 | if ((await sendMsg()) === false) { 420 | msgs = await this.makeMsg(id, pick, [await Bot.makeForwardMsg([{ message: msg }])]) 421 | await sendMsg() 422 | } 423 | 424 | if (rets.data.length === 1) return rets.data[0] 425 | return rets 426 | } 427 | 428 | async recallMsg(id, pick, message_id) { 429 | Bot.makeLog("info", `撤回消息:${message_id}`, id) 430 | if (!Array.isArray(message_id)) message_id = [message_id] 431 | const msgs = [] 432 | for (const i of message_id) msgs.push(await pick.recallMsg(i)) 433 | return msgs 434 | } 435 | 436 | getPick(id, pick, target, prop, receiver) { 437 | switch (prop) { 438 | case "sendMsg": 439 | return this.sendMsg.bind(this, id, pick) 440 | case "recallMsg": 441 | return this.recallMsg.bind(this, id, pick) 442 | case "makeForwardMsg": 443 | return Bot.makeForwardMsg 444 | case "sendForwardMsg": 445 | return async (msg, ...args) => 446 | this.sendMsg(id, pick, await Bot.makeForwardMsg(msg), ...args) 447 | case "getInfo": 448 | return () => 449 | pick.info || 450 | (typeof pick.renew === "function" && pick.renew()) || 451 | (typeof pick.getSimpleInfo === "function" && pick.getSimpleInfo()) 452 | case "pickMember": 453 | case "asMember": 454 | return (...args) => { 455 | for (const i in args) args[i] = Number(args[i]) || args[i] 456 | const pickMember = pick[prop](...args) 457 | return new Proxy( 458 | {}, 459 | { 460 | get: this.getPick.bind(this, id, pickMember), 461 | }, 462 | ) 463 | } 464 | case "raw": 465 | return pick 466 | } 467 | return target[prop] ?? pick[prop] 468 | } 469 | 470 | getBot(id, target, prop, receiver) { 471 | switch (prop) { 472 | case "pickUser": 473 | case "pickFriend": 474 | case "pickGroup": 475 | case "pickMember": 476 | return (...args) => { 477 | for (const i in args) args[i] = Number(args[i]) || args[i] 478 | const pick = target.sdk[prop](...args) 479 | return new Proxy( 480 | {}, 481 | { 482 | get: this.getPick.bind(this, id, pick), 483 | }, 484 | ) 485 | } 486 | } 487 | if (prop in target) return target[prop] 488 | if (typeof target.sdk[prop]?.bind === "function") return target.sdk[prop].bind(target.sdk) 489 | return target.sdk[prop] 490 | } 491 | 492 | makeEvent(data) { 493 | for (const i of ["friend", "group", "member"]) { 494 | if (typeof data[i] !== "object") continue 495 | const pick = data[i] 496 | data[i] = new Proxy( 497 | {}, 498 | { 499 | get: this.getPick.bind(this, data.self_id, pick), 500 | }, 501 | ) 502 | } 503 | 504 | if (data.post_type === "message") 505 | try { 506 | data.raw_message = data.toString() 507 | } catch (err) { 508 | Bot.makeLog("error", err, data.self_id) 509 | } 510 | 511 | if (data.source) { 512 | if (data.source.seq && data.group?.getChatHistory) 513 | data.getReply = async () => (await data.group.getChatHistory(data.source.seq, 1))[0] 514 | else if (data.source.time && data.friend?.getChatHistory) 515 | data.getReply = async () => (await data.friend.getChatHistory(data.source.time, 1))[0] 516 | } 517 | } 518 | 519 | async connect(token, send = Bot.sendMasterMsg.bind(Bot), get) { 520 | token = token.split(":") 521 | const id = Number(token.shift()) 522 | const password = token.shift() 523 | const opts = { 524 | data_dir: `${process.cwd()}/data/icqq/${id}`, 525 | cache_group_member: cfg.bot.cache_group_member, 526 | ...config.bot, 527 | } 528 | const platform = token.shift() 529 | if (platform) opts.platform = Number(platform) 530 | const ver = token.shift() 531 | if (ver) opts.ver = ver 532 | const sign_api_addr = token.join(":") 533 | if (sign_api_addr) opts.sign_api_addr = sign_api_addr 534 | 535 | const bot = icqq.createClient(opts) 536 | const log = {} 537 | for (const i of ["trace", "debug", "info", "mark", "warn", "error", "fatal"]) 538 | log[i] = (...args) => Bot.makeLog(i, args, id) 539 | bot.logger = log 540 | 541 | let getTips = "发送 " 542 | let sendMsg 543 | if (typeof get !== "function") { 544 | getTips += `#Bot验证${id}:` 545 | get = () => 546 | new Promise(resolve => 547 | Bot.once(`verify.${id}`, data => { 548 | send = data.reply 549 | sendMsg = true 550 | resolve(data.msg) 551 | }), 552 | ) 553 | } 554 | 555 | bot.on("system.login.qrcode", async data => { 556 | Bot.em("system.login.qrcode", data) 557 | send([`[${id}] 扫码登录`, segment.image(data.image)]) 558 | for (;;) { 559 | await Bot.sleep(3000) 560 | const { retcode } = await bot.queryQrcodeResult() 561 | switch (retcode) { 562 | case 0: 563 | return bot.qrcodeLogin() 564 | case 17: 565 | return send(`二维码已过期,发送 #Bot上线${id} 重新登录`) 566 | case 54: 567 | return send(`登录取消,发送 #Bot上线${id} 重新登录`) 568 | } 569 | } 570 | }) 571 | 572 | bot.on("system.login.slider", async data => { 573 | Bot.em("system.login.slider", data) 574 | const fnc = {} 575 | if (bot.useNTLogin) { 576 | const url = `https://captcha-nt-api.928100.xyz/?key=${id}` 577 | for (;;) { 578 | const res = await (await fetch(url)).json() 579 | Bot.makeLog("debug", ["Ticket", res], id) 580 | if (res.status == "0") break 581 | await Bot.sleep(3000) 582 | } 583 | send( 584 | `[${id}] 请打开下方链接完成滑动验证\n` + 585 | `https://CapNT.928100.xyz?${new URL(data.url).searchParams.toString()}`, 586 | ) 587 | fnc.ticket = async () => { 588 | const res = await (await fetch(url)).json() 589 | Bot.makeLog("debug", ["Ticket", res], id) 590 | if (res.status != "0" && res.ticket && res.randstr) return `${res.ticket},${res.randstr}` 591 | } 592 | } else { 593 | send( 594 | `[${id}] 请选择滑动验证方式\n` + 595 | `Bot 与浏览器处于同一网络下推荐网页,否则网页反代\n\n` + 596 | `网页反代验证:${getTips}网页反代\n` + 597 | `网页验证:${getTips}网页\n` + 598 | `请求码验证:${getTips}请求码\n` + 599 | `手动验证:${getTips}ticket\n` + 600 | data.url, 601 | ) 602 | const msg = await get() 603 | switch (msg) { 604 | case "网页反代": { 605 | const url = `https://GT.928100.xyz/captcha/slider?key=${id}` 606 | const ws = new (await import("ws")).WebSocket(url) 607 | const wsSend = data => { 608 | Bot.makeLog("debug", [`发送 ${url}`, data], id) 609 | ws.send(JSON.stringify(data)) 610 | } 611 | let ticket 612 | fnc.ticket = () => { 613 | if (ticket instanceof Error) throw ticket 614 | return ticket 615 | } 616 | fnc.close = ws.terminate.bind(ws) 617 | ws.onclose = () => { 618 | Bot.makeLog("debug", `连接关闭 ${url}`, id) 619 | ticket ??= Error(`连接关闭 ${url}`) 620 | } 621 | ws.onerror = ({ error }) => { 622 | Bot.makeLog("debug", [`连接错误 ${url}`, error], id) 623 | ticket ??= Error(`连接错误 ${url}`, { cause: error }) 624 | fnc.close() 625 | } 626 | ws.onopen = () => { 627 | wsSend({ type: "register", payload: { url: data.url } }) 628 | send(url) 629 | } 630 | ws.onmessage = async msg => { 631 | try { 632 | const data = JSON.parse(msg.data) 633 | Bot.makeLog("debug", [`收到 ${url}`, data], id) 634 | switch (data.type) { 635 | case "ticket": 636 | ticket = data.payload.ticket 637 | fnc.close() 638 | break 639 | case "handle": 640 | const { url, ...opts } = data.payload 641 | const req = await fetch(url, opts) 642 | data.payload = { 643 | result: Buffer.from(await req.arrayBuffer()).toString("base64"), 644 | headers: Object.fromEntries(req.headers.entries()), 645 | } 646 | wsSend(data) 647 | break 648 | default: 649 | Bot.makeLog("info", data, id) 650 | } 651 | } catch (err) { 652 | Bot.makeLog("error", err, id) 653 | } 654 | } 655 | break 656 | } 657 | case "网页": { 658 | const url = `https://GT.928100.xyz/captcha/slider?key=${id}` 659 | await fetch(url, { 660 | method: "POST", 661 | headers: { "Content-Type": "application/json" }, 662 | body: JSON.stringify({ url: data.url }), 663 | }) 664 | send(url) 665 | 666 | fnc.ticket = async () => { 667 | const res = await ( 668 | await fetch(url, { 669 | method: "POST", 670 | headers: { "Content-Type": "application/json" }, 671 | body: JSON.stringify({ submit: id }), 672 | }) 673 | ).json() 674 | return res.data?.ticket 675 | } 676 | break 677 | } 678 | case "请求码": { 679 | const url = data.url.replace("ssl.captcha.qq.com", "txhelper.glitch.me") 680 | const code = await (await fetch(url)).text() 681 | send(code) 682 | 683 | fnc.ticket = async () => { 684 | const res = await (await fetch(url)).text() 685 | if (res !== code) return res 686 | } 687 | break 688 | } 689 | default: 690 | return bot.submitSlider(msg) 691 | } 692 | } 693 | try { 694 | for (let i = 0; i < 60; i++) { 695 | await Bot.sleep(3000) 696 | const ticket = await fnc.ticket() 697 | if (ticket) return bot.submitSlider(ticket) 698 | } 699 | } catch (err) { 700 | Bot.makeLog("error", err, id) 701 | return send(`滑动验证错误,发送 #Bot上线${id} 重新登录`) 702 | } 703 | if (fnc.close) fnc.close() 704 | return send(`滑动验证超时,发送 #Bot上线${id} 重新登录`) 705 | }) 706 | 707 | bot.on("system.login.device", async data => { 708 | Bot.em("system.login.device", data) 709 | if (bot.useNTLogin) { 710 | send( 711 | `[${id}] 触发设备验证\n` + 712 | `请在QQ内点击下方链接完成验证, 复制到浏览器无效\n` + 713 | `通过验证后${getTips}继续登录\n\n` + 714 | data.url, 715 | ) 716 | for (;;) { 717 | if ((await get()) === "继续登录") { 718 | bot.login() 719 | break 720 | } 721 | } 722 | } else { 723 | send( 724 | `[${id}] 请选择设备锁验证方式\n` + 725 | `短信验证:${getTips}短信\n` + 726 | `扫码验证:扫码完成后,${getTips}继续登录\n` + 727 | data.url, 728 | ) 729 | for (;;) { 730 | const msg = await get() 731 | if (msg === "短信") { 732 | bot.sendSmsCode() 733 | send(`[${id}] 短信已发送,${getTips}验证码`) 734 | bot.submitSmsCode(await get()) 735 | break 736 | } else if (msg === "继续登录") { 737 | bot.login() 738 | break 739 | } 740 | } 741 | } 742 | }) 743 | 744 | bot.on("system.login.auth", async data => { 745 | Bot.em("system.login.auth", data) 746 | send(`[${id}] 请完成身份验证后,${getTips}继续登录\n${data.url}`) 747 | for (;;) { 748 | if ((await get()) === "继续登录") { 749 | bot.login() 750 | break 751 | } 752 | } 753 | }) 754 | 755 | bot.on("system.login.error", data => { 756 | Bot.em("system.login.error", data) 757 | send(`[${id}] 登录错误:${data.message}(${data.code})\n` + `发送 #Bot上线${id} 重新登录`) 758 | }) 759 | bot.on("system.offline", data => { 760 | const i = Bot.uin.indexOf(id) 761 | if (i !== -1) Bot.uin.splice(i, 1) 762 | Bot.em("system.offline", data) 763 | send(`[${id}] 账号下线:${data.message}\n` + `发送 #Bot上线${id} 重新登录`) 764 | }) 765 | bot.on("system.online", data => { 766 | Bot.em("system.online", data) 767 | bot.logger = log 768 | if (sendMsg) send(`[${id}] 登录完成`) 769 | Bot.em(`connect.${id}`, { self_id: id }) 770 | }) 771 | 772 | Bot[id] = new Proxy( 773 | { 774 | adapter: this, 775 | sdk: bot, 776 | icqq, 777 | avatar: bot.pickFriend(id).getAvatarUrl(), 778 | version: { 779 | id: this.id, 780 | name: this.name, 781 | version: this.version, 782 | }, 783 | uploadImage: this.uploadImage.bind(this, id), 784 | uploadRecord: this.uploadRecord.bind(this, id), 785 | uploadVideo: this.uploadVideo.bind(this, id), 786 | }, 787 | { 788 | get: this.getBot.bind(this, id), 789 | }, 790 | ) 791 | await new Promise(resolve => { 792 | bot.once("system.online", resolve) 793 | bot.login(id, password) 794 | }) 795 | 796 | bot.on("message", data => { 797 | this.makeEvent(data) 798 | Bot.em(`${data.post_type}.${data.message_type}.${data.sub_type}`, data) 799 | }) 800 | 801 | bot.on("notice", data => { 802 | this.makeEvent(data) 803 | Bot.em(`${data.post_type}.${data.notice_type}.${data.sub_type}`, data) 804 | }) 805 | 806 | bot.on("request", data => { 807 | this.makeEvent(data) 808 | Bot.em(`${data.post_type}.${data.request_type}.${data.sub_type}`, data) 809 | }) 810 | 811 | for (const i of ["internal.input", "sync"]) 812 | bot.on(i, data => { 813 | data.self_id = id 814 | Bot.em(i, data) 815 | }) 816 | 817 | Bot.makeLog("mark", `${this.name}(${this.id}) ${this.version} 已连接`, id) 818 | return true 819 | } 820 | 821 | async load() { 822 | for (const token of config.token) await Bot.sleep(5000, this.connect(token)) 823 | } 824 | })() 825 | 826 | Bot.adapter.push(adapter) 827 | 828 | export class ICQQAdapter extends plugin { 829 | constructor() { 830 | super({ 831 | name: "ICQQAdapter", 832 | dsc: "ICQQ 适配器设置", 833 | event: "message", 834 | rule: [ 835 | { 836 | reg: "^#[Qq]+账号$", 837 | fnc: "List", 838 | permission: config.permission, 839 | }, 840 | { 841 | reg: "^#[Qq]+设置[0-9]+", 842 | fnc: "Token", 843 | permission: config.permission, 844 | }, 845 | { 846 | reg: "^#[Qq]+签名.+$", 847 | fnc: "SignUrl", 848 | permission: config.permission, 849 | }, 850 | ], 851 | }) 852 | } 853 | 854 | List() { 855 | this.reply(`共${config.token.length}个账号:\n${config.token.join("\n")}`, true) 856 | } 857 | 858 | async Token() { 859 | const token = this.e.msg.replace(/^#[Qq]+设置/, "").trim() 860 | if (config.token.includes(token)) { 861 | config.token = config.token.filter(item => item !== token) 862 | this.reply(`账号已删除,重启后生效,共${config.token.length}个账号`, true) 863 | } else { 864 | if ( 865 | await adapter.connect(token, msg => this.reply(msg, true), Bot.getTextMsg.bind(Bot, this.e)) 866 | ) { 867 | config.token.push(token) 868 | this.reply(`账号已连接,共${config.token.length}个账号`, true) 869 | } else { 870 | this.reply("账号连接失败", true) 871 | return false 872 | } 873 | } 874 | await configSave() 875 | } 876 | 877 | async SignUrl() { 878 | config.bot.sign_api_addr = this.e.msg.replace(/^#[Qq]+签名/, "").trim() 879 | await configSave() 880 | this.reply("签名已设置,重启后生效", true) 881 | } 882 | } 883 | 884 | logger.info(logger.green("- ICQQ 适配器插件 加载完成")) 885 | --------------------------------------------------------------------------------