Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@hyrious/blivec

Package Overview
Dependencies
Maintainers
1
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@hyrious/blivec - npm Package Compare versions

Comparing version 0.3.8 to 0.3.9

188

dist/bin.js

@@ -9,20 +9,27 @@ #!/usr/bin/env node

import readline from "readline";
import { Connection, getRoomPlayInfo, sendDanmaku, testUrl } from "./index.js";
import { Connection, getRoomPlayInfo, searchRoom, sendDanmaku, stripTags, testUrl } from "./index.js";
const help = `
Usage: bl <room_id> # listen danmaku
--json # print all events in json
Usage:
bl <room_id> # listen danmaku
--json # print all events in json
bl <room_id> <message> # send danmaku
bl <room_id> <message> # send danmaku
bl get <room_id> # get stream url
--json # print them in json
bl get <room_id> # get stream url
--json # print them in json
bl d <room_id> [--interval=1] # dd mode
--interval=<minutes> # set 0 to disable polling
--mpv # open in mpv instead
--on-close=<behavior> # do something on window close
default # restart player
ask # ask quality again
quit # quit DD mode
-- [...player_args] # pass args to ffplay or mpv
bl d <room_id> [--interval=1] # dd mode
--interval=<minutes> # set 0 to disable polling
--mpv # open in mpv instead
--on-close=<behavior> # do something on window close
default # restart player
ask # ask quality again
quit # quit DD mode
-- [...player_args] # pass args to ffplay or mpv
Examples:
bl 123456
bl 123456 "Hello, world!"
bl get 123456
bl d 123456 --mpv --on-close=quit -- --volume=50
`.trim();

@@ -63,3 +70,3 @@ const has_colors = tty.WriteStream.prototype.hasColors();

}
function listen(id, { json = false } = {}) {
function listen(id2, { json = false } = {}) {
let count = 0;

@@ -86,3 +93,3 @@ const events = json ? {

line = line.slice(2);
send(id, line).catch(log.catch_error);
send(id2, line).catch(log.catch_error);
} else {

@@ -109,5 +116,5 @@ log.info('message needs to start with "> " (space is required)');

};
return new Connection(id, events);
return new Connection(id2, events);
}
async function send(id, message) {
async function send(id2, message) {
function example() {

@@ -150,3 +157,3 @@ console.error("Example content:");

if (env.SESSDATA && env.bili_jct) {
await sendDanmaku(id, message, env).catch(log.catch_error);
await sendDanmaku(id2, message, env).catch(log.catch_error);
} else {

@@ -157,5 +164,5 @@ log.error("Invalid cookie.txt");

}
async function get(id, { json = false } = {}) {
async function get(id2, { json = false } = {}) {
try {
const info = await getRoomPlayInfo(id);
const info = await getRoomPlayInfo(id2);
if (!json) {

@@ -179,4 +186,4 @@ console.log("Title:", info.title);

}
async function D(id, { interval = 1, mpv = false, on_close = "default", args = [] } = {}) {
log.info(`DD ${id} ${interval > 0 ? `every ${interval} minutes` : "once"}`);
async function D(id2, { interval = 1, mpv = false, on_close = "default", args = [] } = {}) {
log.info(`DD ${id2} ${interval > 0 ? `every ${interval} minutes` : "once"}`);
let con;

@@ -191,3 +198,3 @@ let child;

while (info === null) {
info = await getRoomPlayInfo(id).catch(() => null);
info = await getRoomPlayInfo(id2).catch(() => null);
if (info && !await testUrl(first(info.streams).url, headers))

@@ -288,3 +295,3 @@ info = null;

child = play(info.streams[selected].url, info.title, args);
con ||= listen(id);
con ||= listen(id2);
con.resume();

@@ -327,57 +334,92 @@ child.on("exit", () => {

const [arg1, arg2, ...rest] = process.argv.slice(2);
if (arg1 === void 0 || arg1 === "--help" || arg2 === "--help" || rest.includes("--help")) {
console.log(help);
process.exit(0);
}
let action = "listen";
let id_or_keyword;
let id;
if (arg1 === "get" || arg1 === "d" || arg1 === "dd") {
const id = Number.parseInt(arg2);
if (Number.isSafeInteger(id) && id > 0) {
if (arg1 === "get") {
const json = rest.includes("--json");
await get(id, { json });
} else {
let interval = 1;
let mpv = false;
let on_close = "default";
let args;
for (const arg of rest) {
if (arg.startsWith("--interval=")) {
const value = Number.parseInt(arg.slice(11));
if (Number.isFinite(value)) {
interval = Math.max(0, value);
} else {
log.error("Invalid interval, expect a number >= 0");
process.exit(1);
}
} else if (arg.startsWith("--on-close=")) {
const value = arg.slice(11);
if (["default", "ask", "quit", "exit"].includes(value)) {
on_close = value;
} else {
log.error("Invalid on-close option, expect 'default' 'ask' 'quit'");
process.exit(1);
}
} else if (arg === "--mpv") {
mpv = true;
} else if (arg === "--") {
args = [];
} else if (args) {
args.push(arg);
}
}
const con = await D(id, { interval, mpv, on_close, args });
con && sigint(con);
action = arg1;
id_or_keyword = arg2;
} else {
id_or_keyword = arg1;
}
let maybe_id = Number.parseInt(id_or_keyword);
if (Number.isSafeInteger(maybe_id) && maybe_id > 0) {
id = maybe_id;
} else {
let rooms = await searchRoom(id_or_keyword);
if (rooms.length === 0) {
log.error("Not found room with keyword " + JSON.stringify(id_or_keyword));
process.exit(1);
} else if (rooms.length === 1) {
id = rooms[0].roomid;
} else {
log.info("Found multiple rooms:");
const choices = [];
for (let i2 = 0; i2 < rooms.length; i2++) {
const room = rooms[i2];
const title = stripTags(room.title);
log.info(` ${String(i2 + 1).padStart(2)}: ${room.uname} - ${title}`);
choices.push(i2 + 1);
}
choices.push("Y=1", "n");
const repl2 = setup_repl();
const answer = await new Promise((resolve) => {
repl2.question(`Choose a room, or give up: (${choices.join("/")}) `, (a) => resolve(a || "Y"));
});
let selected = rooms[0];
let i = Number.parseInt(answer);
if (Number.isSafeInteger(i) && 1 <= i && i <= rooms.length) {
selected = rooms[i - 1];
} else if (answer[0].toLowerCase() === "n") {
process.exit(0);
}
id = selected.roomid;
}
}
if (action === "listen") {
const json = arg2 === "--json";
if (arg2 && !json) {
await send(id, arg2);
} else {
console.log(help);
const con = listen(id, { json });
sigint(con, { json });
}
} else if (action === "get") {
const json = rest.includes("--json");
await get(id, { json });
} else {
const id = Number.parseInt(arg1);
const json = arg2 === "--json";
if (Number.isSafeInteger(id) && id > 0) {
if (arg2 && !json) {
await send(id, arg2);
} else {
const con = listen(id, { json });
sigint(con, { json });
let interval = 1;
let mpv = false;
let on_close = "default";
let args;
for (const arg of rest) {
if (arg.startsWith("--interval=")) {
const value = Number.parseInt(arg.slice(11));
if (Number.isFinite(value)) {
interval = Math.max(0, value);
} else {
log.error("Invalid interval, expect a number >= 0");
process.exit(1);
}
} else if (arg.startsWith("--on-close=")) {
const value = arg.slice(11);
if (["default", "ask", "quit", "exit"].includes(value)) {
on_close = value;
} else {
log.error("Invalid on-close option, expect 'default' 'ask' 'quit'");
process.exit(1);
}
} else if (arg === "--mpv") {
mpv = true;
} else if (arg === "--") {
args = [];
} else if (args) {
args.push(arg);
}
} else {
console.log(help);
}
const con = await D(id, { interval, mpv, on_close, args });
con && sigint(con);
}

@@ -81,4 +81,12 @@ import { Socket } from 'net';

}>;
declare function searchRoom(keyword: string): Promise<{
roomid: number;
uname: string;
title: string;
live_time: string;
cover: string;
}[]>;
declare function testUrl(url: string, headers?: string[]): false | Promise<boolean>;
declare function stripTags(html: string): string;
export { Connection, ConnectionInfo, DanmuInfo, Env, Events, RoomInfo, getDanmuInfo, getRoomInfo, getRoomPlayInfo, sendDanmaku, testUrl };
export { Connection, ConnectionInfo, DanmuInfo, Env, Events, RoomInfo, getDanmuInfo, getRoomInfo, getRoomPlayInfo, searchRoom, sendDanmaku, stripTags, testUrl };

@@ -14,3 +14,3 @@ "use strict";

};
const get = (url) => new Promise((resolve, reject) => https.get(url, text(resolve)).on("error", reject));
const get = (url, options = {}) => new Promise((resolve, reject) => https.get(url, options, text(resolve)).on("error", reject));
const inflateAsync = /* @__PURE__ */ promisify(inflate);

@@ -294,2 +294,17 @@ const brotliDecompressAsync = /* @__PURE__ */ promisify(brotliDecompress);

}
export async function searchRoom(keyword) {
keyword = encodeURIComponent(keyword);
const api = "https://api.bilibili.com/x/web-interface/search/type";
const params = "&order=online&coverType=user_cover&page=1";
const info = await get(`${api}?search_type=live_room&keyword=${keyword}${params}`, {
headers: {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.1) Gecko/20100101 Firefox/60.1",
"Referer": `https://search.bilibili.com/live?keyword=${keyword}${params}&search_type=live`
}
});
const { code, message, data } = JSON.parse(info);
if (code != 0)
throw new Error(message);
return data.result;
}
export function testUrl(url, headers = []) {

@@ -307,1 +322,4 @@ if (!url)

}
export function stripTags(html) {
return html.replace(/<[^>]+>/g, "");
}
{
"name": "@hyrious/blivec",
"version": "0.3.8",
"version": "0.3.9",
"description": "bilibili live cli",

@@ -5,0 +5,0 @@ "type": "module",

@@ -8,21 +8,28 @@ #!/usr/bin/env node

import readline from "readline";
import { Connection, Events, getRoomPlayInfo, sendDanmaku, testUrl } from "./index.js";
import { Connection, Events, getRoomPlayInfo, searchRoom, sendDanmaku, stripTags, testUrl } from "./index.js";
const help = `
Usage: bl <room_id> # listen danmaku
--json # print all events in json
Usage:
bl <room_id> # listen danmaku
--json # print all events in json
bl <room_id> <message> # send danmaku
bl <room_id> <message> # send danmaku
bl get <room_id> # get stream url
--json # print them in json
bl get <room_id> # get stream url
--json # print them in json
bl d <room_id> [--interval=1] # dd mode
--interval=<minutes> # set 0 to disable polling
--mpv # open in mpv instead
--on-close=<behavior> # do something on window close
default # restart player
ask # ask quality again
quit # quit DD mode
-- [...player_args] # pass args to ffplay or mpv
bl d <room_id> [--interval=1] # dd mode
--interval=<minutes> # set 0 to disable polling
--mpv # open in mpv instead
--on-close=<behavior> # do something on window close
default # restart player
ask # ask quality again
quit # quit DD mode
-- [...player_args] # pass args to ffplay or mpv
Examples:
bl 123456
bl 123456 "Hello, world!"
bl get 123456
bl d 123456 --mpv --on-close=quit -- --volume=50
`.trim();

@@ -349,58 +356,97 @@

const [arg1, arg2, ...rest] = process.argv.slice(2);
if (arg1 === void 0 || arg1 === "--help" || arg2 === "--help" || rest.includes("--help")) {
console.log(help);
process.exit(0);
}
let action = "listen";
let id_or_keyword: string;
let id: number;
if (arg1 === "get" || arg1 === "d" || arg1 === "dd") {
const id = Number.parseInt(arg2);
if (Number.isSafeInteger(id) && id > 0) {
if (arg1 === "get") {
const json = rest.includes("--json");
await get(id, { json });
} else {
let interval = 1;
let mpv = false;
let on_close = "default";
let args: string[] | undefined;
for (const arg of rest) {
if (arg.startsWith("--interval=")) {
const value = Number.parseInt(arg.slice(11));
if (Number.isFinite(value)) {
interval = Math.max(0, value);
} else {
log.error("Invalid interval, expect a number >= 0");
process.exit(1);
}
} else if (arg.startsWith("--on-close=")) {
const value = arg.slice(11);
if (["default", "ask", "quit", "exit"].includes(value)) {
on_close = value;
} else {
log.error("Invalid on-close option, expect 'default' 'ask' 'quit'");
process.exit(1);
}
} else if (arg === "--mpv") {
mpv = true;
} else if (arg === "--") {
args = [];
} else if (args) {
args.push(arg);
}
}
const con = await D(id, { interval, mpv, on_close, args });
con && sigint(con);
action = arg1;
id_or_keyword = arg2;
} else {
id_or_keyword = arg1;
}
// resolve keyword to room id
let maybe_id = Number.parseInt(id_or_keyword);
if (Number.isSafeInteger(maybe_id) && maybe_id > 0) {
id = maybe_id;
} else {
let rooms = await searchRoom(id_or_keyword);
if (rooms.length === 0) {
log.error("Not found room with keyword " + JSON.stringify(id_or_keyword));
process.exit(1);
} else if (rooms.length === 1) {
id = rooms[0].roomid;
} else {
log.info("Found multiple rooms:");
const choices: Array<number | string> = [];
for (let i = 0; i < rooms.length; i++) {
const room = rooms[i];
const title = stripTags(room.title);
log.info(` ${String(i + 1).padStart(2)}: ${room.uname} - ${title}`);
choices.push(i + 1);
}
choices.push("Y=1", "n");
const repl = setup_repl();
const answer = await new Promise<string>((resolve) => {
repl.question(`Choose a room, or give up: (${choices.join("/")}) `, (a) => resolve(a || "Y"));
});
let selected = rooms[0];
let i = Number.parseInt(answer);
if (Number.isSafeInteger(i) && 1 <= i && i <= rooms.length) {
selected = rooms[i - 1];
} else if (answer[0].toLowerCase() === "n") {
process.exit(0);
}
id = selected.roomid;
}
}
if (action === "listen") {
const json = arg2 === "--json";
if (arg2 && !json) {
await send(id, arg2);
} else {
console.log(help);
const con = listen(id, { json });
sigint(con, { json });
}
} else if (action === "get") {
const json = rest.includes("--json");
await get(id, { json });
} else {
const id = Number.parseInt(arg1);
const json = arg2 === "--json";
if (Number.isSafeInteger(id) && id > 0) {
if (arg2 && !json) {
await send(id, arg2);
} else {
const con = listen(id, { json });
sigint(con, { json });
let interval = 1;
let mpv = false;
let on_close = "default";
let args: string[] | undefined;
for (const arg of rest) {
if (arg.startsWith("--interval=")) {
const value = Number.parseInt(arg.slice(11));
if (Number.isFinite(value)) {
interval = Math.max(0, value);
} else {
log.error("Invalid interval, expect a number >= 0");
process.exit(1);
}
} else if (arg.startsWith("--on-close=")) {
const value = arg.slice(11);
if (["default", "ask", "quit", "exit"].includes(value)) {
on_close = value;
} else {
log.error("Invalid on-close option, expect 'default' 'ask' 'quit'");
process.exit(1);
}
} else if (arg === "--mpv") {
mpv = true;
} else if (arg === "--") {
args = [];
} else if (args) {
args.push(arg);
}
} else {
console.log(help);
}
const con = await D(id, { interval, mpv, on_close, args });
con && sigint(con);
}

@@ -15,4 +15,4 @@ import https from "https";

const get = (url: string) =>
new Promise<string>((resolve, reject) => https.get(url, text(resolve)).on("error", reject));
const get = (url: string, options: https.RequestOptions = {}) =>
new Promise<string>((resolve, reject) => https.get(url, options, text(resolve)).on("error", reject));

@@ -405,2 +405,31 @@ const inflateAsync = /* @__PURE__ */ promisify(inflate);

interface SerachResult {
result: {
roomid: number;
// player name
uname: string;
// may include html tags
title: string;
// start time
live_time: string;
// screen shot
cover: string;
}[];
}
export async function searchRoom(keyword: string) {
keyword = encodeURIComponent(keyword);
const api = "https://api.bilibili.com/x/web-interface/search/type";
const params = "&order=online&coverType=user_cover&page=1";
const info = await get(`${api}?search_type=live_room&keyword=${keyword}${params}`, {
headers: {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:60.1) Gecko/20100101 Firefox/60.1",
"Referer": `https://search.bilibili.com/live?keyword=${keyword}${params}&search_type=live`,
},
});
const { code, message, data } = JSON.parse(info);
if (code != 0) throw new Error(message);
return (data as SerachResult).result;
}
export function testUrl(url: string, headers: string[] = []) {

@@ -419,1 +448,5 @@ if (!url) return false;

}
export function stripTags(html: string) {
return html.replace(/<[^>]+>/g, "");
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc