@hyrious/blivec
Advanced tools
Comparing version 0.1.0 to 0.1.1
#!/usr/bin/env node | ||
import { Connection } from "./index.js"; | ||
const [raw_id] = process.argv.slice(2); | ||
import fs from "fs"; | ||
import path from "path"; | ||
import { getTempDir, Connection, input, sendDanmaku } from "./index.js"; | ||
const [raw_id, message] = process.argv.slice(2); | ||
const id = Number.parseInt(raw_id); | ||
@@ -8,20 +10,61 @@ const safe = Number.isSafeInteger(id) && id > 0; | ||
console.log("Usage: bl <room_id>"); | ||
console.log(' bl <room_id> "message-to-send" (requires cookie)'); | ||
process.exit(0); | ||
} | ||
const con = new Connection(id, { | ||
init({ title }) { | ||
console.log(`listening ${title}`); | ||
}, | ||
message(data) { | ||
if (typeof data === "object" && data !== null && data.cmd === "DANMU_MSG") { | ||
const message = data.info[1]; | ||
const user = data.info[2][1]; | ||
console.log(">", `[${user}]`, message); | ||
if (message) { | ||
const tmpdir = getTempDir("blivec"); | ||
fs.mkdirSync(tmpdir, { recursive: true }); | ||
const cookie_file = path.join(tmpdir, "cookie.txt"); | ||
let cookie = ""; | ||
try { | ||
cookie = fs.readFileSync(cookie_file, "utf8"); | ||
} catch { | ||
} | ||
if (!cookie) { | ||
console.log("Not found cached cookie, please login on bilibili and"); | ||
console.log("find `SESSDATA` and `bili_jct` from cookies."); | ||
console.log(); | ||
console.log("The `SESSDATA` can only be found through cookies panel."); | ||
console.log(); | ||
console.log("The `bili_jct` can be copied through this script:"); | ||
console.log("cookieStore.get('bili_jct').then(e=>copy(e.value))"); | ||
console.log(); | ||
const SESSDATA = await input("Paste `SESSDATA` here: "); | ||
const bili_jct = await input("Paste `bili_jct` here: "); | ||
cookie = JSON.stringify({ SESSDATA, bili_jct }); | ||
fs.writeFileSync(cookie_file, cookie); | ||
} | ||
try { | ||
const ret = await sendDanmaku(id, message, JSON.parse(cookie)); | ||
const json = JSON.parse(ret); | ||
if (json.code != 0) { | ||
throw new Error(json.message); | ||
} | ||
}, | ||
error: console.error | ||
}); | ||
process.on("SIGINT", () => { | ||
console.log("closing..."); | ||
con.close(); | ||
}); | ||
console.log("Message sent."); | ||
} catch (err) { | ||
console.error(err); | ||
fs.rmSync(cookie_file, { maxRetries: 3, recursive: true }); | ||
console.log("Deleted cookie. Please try again."); | ||
} | ||
} else { | ||
let is_object = function(a) { | ||
return typeof a === "object" && a !== null; | ||
}; | ||
const con = new Connection(id, { | ||
init({ title }) { | ||
console.log(`listening ${title}`); | ||
}, | ||
message(data) { | ||
if (is_object(data) && data.cmd === "DANMU_MSG") { | ||
const message2 = data.info[1]; | ||
const user = data.info[2][1]; | ||
console.log(">", `[${user}]`, message2); | ||
} | ||
}, | ||
error: console.error | ||
}); | ||
process.on("SIGINT", () => { | ||
console.log("closing..."); | ||
con.close(); | ||
}); | ||
} |
@@ -0,1 +1,19 @@ | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
import os from "os"; | ||
import path from "path"; | ||
import https from "https"; | ||
@@ -5,2 +23,37 @@ import { createConnection } from "net"; | ||
import { promisify } from "util"; | ||
const post = typeof fetch !== "undefined" ? (url, body, params) => fetch(url, __spreadValues({ method: "POST", body }, params)).then((r) => r.text()) : (url, body, params) => new Promise((resolve, reject) => https.request(url, __spreadValues({ method: "POST", timeout: 1e3 }, params), (res) => { | ||
const chunks = []; | ||
res.on("data", chunks.push.bind(chunks)); | ||
res.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); | ||
}).end(body).on("error", reject)); | ||
export function getTempDir(name) { | ||
const tmpdir = os.tmpdir(); | ||
const platform = process.platform; | ||
if (platform === "darwin" || platform === "win32") { | ||
return path.join(tmpdir, name); | ||
} | ||
const username = path.basename(os.homedir()); | ||
return path.join(tmpdir, username, name); | ||
} | ||
export function sendDanmaku(id, message, { SESSDATA, bili_jct }) { | ||
const t = Date.now() / 1e3 | 0; | ||
const headers = { | ||
Cookie: `SESSDATA=${SESSDATA}`, | ||
"Content-Type": "application/x-www-form-urlencoded" | ||
}; | ||
const body = `color=16777215&fontsize=25&mode=1&msg=${encodeURIComponent(message)}&rnd=${t}&roomid=${id}&csrf=${bili_jct}&csrf_token=${bili_jct}`; | ||
return post("https://api.live.bilibili.com/msg/send", body, { headers }); | ||
} | ||
export function input(prompt) { | ||
return new Promise((resolve, reject) => { | ||
const stdin = process.stdin; | ||
stdin.setEncoding("utf8"); | ||
stdin.on("data", (data) => { | ||
stdin.resume(); | ||
resolve(String(data).trim()); | ||
}); | ||
stdin.on("error", reject); | ||
process.stdout.write(prompt); | ||
}); | ||
} | ||
const inflateAsync = /* @__PURE__ */ promisify(inflate); | ||
@@ -7,0 +60,0 @@ const brotliDecompressAsync = /* @__PURE__ */ promisify(brotliDecompress); |
{ | ||
"name": "@hyrious/blivec", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "bilibili live danmaku cli", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -24,2 +24,5 @@ ## <samp>> <ins>b</ins>ilibili-<ins>live</ins>-<ins>c</ins>li</samp> | ||
bl 14917277 | ||
# send danmaku (requires cookie) | ||
bl 14917277 "hello world" | ||
``` | ||
@@ -26,0 +29,0 @@ |
#!/usr/bin/env node | ||
import { Connection } from "./index.js"; | ||
import fs from "fs"; | ||
import path from "path"; | ||
import { getTempDir, Connection, input, sendDanmaku } from "./index.js"; | ||
const [raw_id] = process.argv.slice(2); | ||
const [raw_id, message] = process.argv.slice(2); | ||
const id = Number.parseInt(raw_id); | ||
@@ -10,22 +12,63 @@ const safe = Number.isSafeInteger(id) && id > 0; | ||
console.log("Usage: bl <room_id>"); | ||
console.log(' bl <room_id> "message-to-send" (requires cookie)'); | ||
process.exit(0); | ||
} | ||
const con = new Connection(id, { | ||
init({ title }) { | ||
console.log(`listening ${title}`); | ||
}, | ||
message(data) { | ||
if (typeof data === "object" && data !== null && data.cmd === "DANMU_MSG") { | ||
const message = data.info[1]; | ||
const user = data.info[2][1]; | ||
console.log(">", `[${user}]`, message); | ||
if (message) { | ||
const tmpdir = getTempDir("blivec"); | ||
fs.mkdirSync(tmpdir, { recursive: true }); | ||
const cookie_file = path.join(tmpdir, "cookie.txt"); | ||
let cookie = ""; | ||
try { | ||
cookie = fs.readFileSync(cookie_file, "utf8"); | ||
} catch {} | ||
if (!cookie) { | ||
console.log("Not found cached cookie, please login on bilibili and"); | ||
console.log("find `SESSDATA` and `bili_jct` from cookies."); | ||
console.log(); | ||
console.log("The `SESSDATA` can only be found through cookies panel."); | ||
console.log(); | ||
console.log("The `bili_jct` can be copied through this script:"); | ||
console.log("cookieStore.get('bili_jct').then(e=>copy(e.value))"); | ||
console.log(); | ||
const SESSDATA = await input("Paste `SESSDATA` here: "); | ||
const bili_jct = await input("Paste `bili_jct` here: "); | ||
cookie = JSON.stringify({ SESSDATA, bili_jct }); | ||
fs.writeFileSync(cookie_file, cookie); | ||
} | ||
try { | ||
const ret = await sendDanmaku(id, message, JSON.parse(cookie)); | ||
const json = JSON.parse(ret); | ||
if (json.code != 0) { | ||
throw new Error(json.message); | ||
} | ||
}, | ||
error: console.error, | ||
}); | ||
console.log("Message sent."); | ||
} catch (err) { | ||
console.error(err); | ||
fs.rmSync(cookie_file, { maxRetries: 3, recursive: true }); | ||
console.log("Deleted cookie. Please try again."); | ||
} | ||
} else { | ||
function is_object(a: any) { | ||
return typeof a === "object" && a !== null; | ||
} | ||
process.on("SIGINT", () => { | ||
console.log("closing..."); | ||
con.close(); | ||
}); | ||
const con = new Connection(id, { | ||
init({ title }) { | ||
console.log(`listening ${title}`); | ||
}, | ||
message(data) { | ||
if (is_object(data) && data.cmd === "DANMU_MSG") { | ||
const message = data.info[1]; | ||
const user = data.info[2][1]; | ||
console.log(">", `[${user}]`, message); | ||
} | ||
}, | ||
error: console.error, | ||
}); | ||
process.on("SIGINT", () => { | ||
console.log("closing..."); | ||
con.close(); | ||
}); | ||
} |
@@ -0,1 +1,3 @@ | ||
import os from "os"; | ||
import path from "path"; | ||
import https from "https"; | ||
@@ -6,2 +8,67 @@ import { Socket, createConnection } from "net"; | ||
// since Node.js 17.5 | ||
// TODO: remove this declaration when @types/node is updated | ||
declare function fetch( | ||
url: string, | ||
init?: { method: string; body: string } | ||
): Promise<{ text: () => string }>; | ||
const post = | ||
typeof fetch !== "undefined" | ||
? (url: string, body: string, params: any) => | ||
fetch(url, { method: "POST", body, ...params }).then(r => r.text()) | ||
: (url: string, body: string, params: any) => | ||
new Promise<string>((resolve, reject) => | ||
https | ||
.request(url, { method: "POST", timeout: 1000, ...params }, res => { | ||
const chunks: Buffer[] = []; | ||
res.on("data", chunks.push.bind(chunks)); | ||
res.on("end", () => | ||
resolve(Buffer.concat(chunks).toString("utf8")) | ||
); | ||
}) | ||
.end(body) | ||
.on("error", reject) | ||
); | ||
export function getTempDir(name: string) { | ||
const tmpdir = os.tmpdir(); | ||
const platform = process.platform; | ||
if (platform === "darwin" || platform === "win32") { | ||
return path.join(tmpdir, name); | ||
} | ||
const username = path.basename(os.homedir()); | ||
return path.join(tmpdir, username, name); | ||
} | ||
export function sendDanmaku( | ||
id: number, | ||
message: string, | ||
{ SESSDATA, bili_jct }: { SESSDATA: string; bili_jct: string } | ||
) { | ||
const t = (Date.now() / 1000) | 0; | ||
const headers = { | ||
Cookie: `SESSDATA=${SESSDATA}`, | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
}; | ||
const body = | ||
`color=16777215&fontsize=25&mode=1` + | ||
`&msg=${encodeURIComponent(message)}` + | ||
`&rnd=${t}&roomid=${id}&csrf=${bili_jct}&csrf_token=${bili_jct}`; | ||
return post("https://api.live.bilibili.com/msg/send", body, { headers }); | ||
} | ||
export function input(prompt: string) { | ||
return new Promise<string>((resolve, reject) => { | ||
const stdin = process.stdin; | ||
stdin.setEncoding("utf8"); | ||
stdin.on("data", data => { | ||
stdin.resume(); | ||
resolve(String(data).trim()); | ||
}); | ||
stdin.on("error", reject); | ||
process.stdout.write(prompt); | ||
}); | ||
} | ||
const inflateAsync = /** @__PURE__ */ promisify(inflate); | ||
@@ -14,6 +81,2 @@ const brotliDecompressAsync = /** @__PURE__ */ promisify(brotliDecompress); | ||
// since Node.js 17.5 | ||
// TODO: remove this declaration when @types/node is updated | ||
declare function fetch(url: string): Promise<{ text: () => string }>; | ||
const get = | ||
@@ -20,0 +83,0 @@ typeof fetch !== "undefined" |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24150
633
46
2
6