diff --git a/bot/bun.lock b/bot/bun.lock index c94ade6..765a9e2 100644 --- a/bot/bun.lock +++ b/bot/bun.lock @@ -11,9 +11,11 @@ "libsodium-wrappers": "^0.7.15", "opusscript": "^0.1.1", "prism-media": "^1.3.5", + "qrcode": "^1.5.4", }, "devDependencies": { "@types/node": "^22.7.0", + "@types/qrcode": "^1.5.6", "typescript": "^5.6.3", }, "optionalDependencies": { @@ -207,6 +209,8 @@ "@types/node": ["@types/node@22.19.20", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-6tELRwSDYWW9EdZhbeZmYGZ1/7Djkt+Ah3/ScEYT9cDord7UJzasR/4D3VONg9tQI5CDp+/CZC1AXj2pCFOvpw=="], + "@types/qrcode": ["@types/qrcode@1.5.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="], diff --git a/bot/package.json b/bot/package.json index 7ccf167..bb785e2 100644 --- a/bot/package.json +++ b/bot/package.json @@ -16,7 +16,8 @@ "dotenv": "^16.4.5", "libsodium-wrappers": "^0.7.15", "opusscript": "^0.1.1", - "prism-media": "^1.3.5" + "prism-media": "^1.3.5", + "qrcode": "^1.5.4" }, "optionalDependencies": { "@dank074/discord-video-stream": "^6.0.0", @@ -24,6 +25,7 @@ }, "devDependencies": { "@types/node": "^22.7.0", + "@types/qrcode": "^1.5.6", "typescript": "^5.6.3" } } diff --git a/bot/src/get-token.ts b/bot/src/get-token.ts index 28b2431..15080c3 100644 --- a/bot/src/get-token.ts +++ b/bot/src/get-token.ts @@ -18,11 +18,14 @@ */ import { readFileSync, writeFileSync, existsSync } from "node:fs"; import { fileURLToPath } from "node:url"; +import QRCode from "qrcode"; // Optional native peer dep; only needed for this helper. // @ts-ignore - provided by discord.js-selfbot-v13 (optionalDependency) import { DiscordAuthWebsocket } from "discord.js-selfbot-v13"; const ENV_PATH = fileURLToPath(new URL("../../.env", import.meta.url)); +// Where to write the scannable QR image (so it can be sent to the user). +const QR_OUT = process.env.QR_OUT || "/tmp/javis_qr.png"; function upsertEnv(key: string, value: string) { let lines: string[] = []; @@ -41,11 +44,19 @@ function upsertEnv(key: string, value: string) { async function main() { const ws: any = new DiscordAuthWebsocket(); - ws.on("ready", () => { + ws.on("ready", async () => { + // Render the auth URL as a scannable QR PNG. Show it on a SECOND screen + // (PC monitor) and scan it with the Discord mobile app's QR scanner. + try { + await QRCode.toFile(QR_OUT, ws.AuthURL, { width: 512, margin: 2 }); + } catch (e) { + console.error("QR 생성 실패:", e); + } console.log("\n================ DISCORD REMOTE LOGIN ================"); - console.log("아래 링크를 디스코드 앱이 깔린 폰에서 여세요 (버너 계정으로 로그인된 상태!):"); - console.log("\nAUTH_URL: " + ws.AuthURL + "\n"); - console.log("열면 '새 기기 로그인' 승인 화면이 뜹니다. 승인하면 토큰이 자동 저장됩니다."); + console.log("QR_IMAGE: " + QR_OUT); + console.log("AUTH_URL: " + ws.AuthURL); + console.log("\nPC/두 번째 화면에 위 QR을 띄우고, 디스코드 모바일 앱의 QR 스캐너로 스캔하세요"); + console.log("(버너 계정으로 로그인된 상태!). 승인하면 토큰이 자동 저장됩니다."); console.log("링크는 약 2분 후 만료됩니다."); console.log("=====================================================\n"); });