@hyrious/blivec
Advanced tools
Comparing version 0.3.3 to 0.3.4
@@ -55,2 +55,17 @@ "use strict"; | ||
timer_heartbeat = /* @__PURE__ */ setTimeout(noop); | ||
_temp = null; | ||
pause() { | ||
this._temp || (this._temp = []); | ||
(this.events.pause || noop)(); | ||
} | ||
resume() { | ||
(this.events.resume || noop)(); | ||
const temp = this._temp; | ||
if (temp) { | ||
this._temp = null; | ||
for (const data of temp) { | ||
(this.events.message || noop)(data); | ||
} | ||
} | ||
} | ||
_closed = false; | ||
@@ -70,3 +85,7 @@ _connect_index = 0; | ||
this.buffer = EMPTY_BUFFER; | ||
const socket = await this.connect(); | ||
const socket = await this.connect().catch(() => null); | ||
if (socket === null) { | ||
this._on_close(); | ||
return; | ||
} | ||
this.socket = socket; | ||
@@ -105,2 +124,3 @@ this.timer_reconnect = setTimeout(this.reconnect.bind(this), 45e3); | ||
(this.events.error || noop)(err); | ||
this.socket = null; | ||
} | ||
@@ -133,3 +153,7 @@ _on_data(buffer) { | ||
} else if (type === "message") { | ||
(this.events.message || noop)(data); | ||
if (this._temp) { | ||
this._temp.push(data); | ||
} else { | ||
(this.events.message || noop)(data); | ||
} | ||
} | ||
@@ -136,0 +160,0 @@ } |
250
dist/bin.js
@@ -5,2 +5,3 @@ #!/usr/bin/env node | ||
import fs from "fs"; | ||
import tty from "tty"; | ||
import { join } from "path"; | ||
@@ -29,9 +30,27 @@ import rl from "readline"; | ||
`.trim(); | ||
const hasColors = tty.WriteStream.prototype.hasColors(); | ||
function help() { | ||
console.log(help_text); | ||
} | ||
function format(beg, end) { | ||
return hasColors ? (str) => "\x1B[" + beg + "m" + str + "\x1B[" + end + "m" : (str) => str; | ||
} | ||
const red = format(31, 39); | ||
const cyan = format(36, 39); | ||
const black = format(30, 39); | ||
const bgRed = format(41, 49); | ||
function print_error(msg) { | ||
console.error(`${bgRed(black("\u2009ERROR\u2009"))} ${red(msg)}`); | ||
} | ||
function print_info(msg) { | ||
console.error(`${cyan("\u2009INFO\u2009")} ${cyan(msg)}`); | ||
} | ||
function error_exit(error) { | ||
print_error(error.message); | ||
process.exit(1); | ||
} | ||
function listen(id, { json = false } = {}) { | ||
let repl; | ||
function setup_repl() { | ||
if (process.stdout.isTTY) { | ||
if (process.stdout.isTTY && !repl) { | ||
console.log('[blivec] type "> message" to send danmaku'); | ||
@@ -49,3 +68,5 @@ repl = rl.createInterface({ | ||
line = line.slice(2); | ||
send(id, line).catch(console.error); | ||
send(id, line).catch((error) => { | ||
print_error(error.message); | ||
}); | ||
} else { | ||
@@ -63,15 +84,21 @@ console.log( | ||
} | ||
let first = 0; | ||
const events = json ? { | ||
init: (data) => console.log(JSON.stringify({ cmd: "init", data })), | ||
message: (data) => console.log(JSON.stringify(data)), | ||
error: console.error | ||
error: (err) => print_error(err.message) | ||
} : { | ||
init({ title, live_status, live_start_time }) { | ||
if (live_status === 1) { | ||
const time = new Date(live_start_time * 1e3).toLocaleString(); | ||
console.log(`[blivec] listening ${title} (start at ${time})`); | ||
if (first === 0) { | ||
if (live_status === 1) { | ||
const time = new Date(live_start_time * 1e3).toLocaleString(); | ||
console.log(`[blivec] listening ${title} (start at ${time})`); | ||
} else { | ||
console.log(`[blivec] listening ${title} (offline)`); | ||
} | ||
setup_repl(); | ||
} else { | ||
console.log(`[blivec] listening ${title} (offline)`); | ||
print_info(`reconnected (x${first})`); | ||
} | ||
setup_repl(); | ||
first++; | ||
}, | ||
@@ -85,4 +112,6 @@ message(a) { | ||
}, | ||
error: console.error, | ||
quit: () => repl && repl.close() | ||
error: (err) => print_error(err.message), | ||
quit: () => repl && repl.close(), | ||
pause: () => repl && repl.pause(), | ||
resume: () => repl && repl.resume() | ||
}; | ||
@@ -93,7 +122,7 @@ return new Connection(id, events); | ||
function example() { | ||
console.log("Example content:"); | ||
console.log(""); | ||
console.log("SESSDATA=..."); | ||
console.log("bili_jct=..."); | ||
console.log(); | ||
console.error("Example content:"); | ||
console.error(""); | ||
console.error("SESSDATA=..."); | ||
console.error("bili_jct=..."); | ||
console.error(); | ||
} | ||
@@ -115,3 +144,3 @@ function cookiePath(path2) { | ||
if (!path) { | ||
console.log('Please create a file "cookie.txt" in current directory.'); | ||
console.error('Please create a file "cookie.txt" in current directory.'); | ||
example(); | ||
@@ -131,5 +160,7 @@ process.exit(1); | ||
if (env.SESSDATA && env.bili_jct) { | ||
await sendDanmaku(id, message, env).catch(console.error); | ||
await sendDanmaku(id, message, env).catch((err) => { | ||
print_error(err.message); | ||
}); | ||
} else { | ||
console.log("Invalid cookie.txt"); | ||
print_error("Invalid cookie.txt"); | ||
example(); | ||
@@ -158,7 +189,12 @@ process.exit(1); | ||
} catch (err) { | ||
console.error("Error:", err.message); | ||
process.exit(1); | ||
error_exit(err); | ||
} | ||
} | ||
async function D(id, { interval = 1, mpv = false } = {}) { | ||
console.log( | ||
`[blivec] DD ${id}`, | ||
interval > 0 ? `every ${interval} minutes` : "once" | ||
); | ||
let con; | ||
let child; | ||
const headers = [ | ||
@@ -168,79 +204,109 @@ "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.1) Gecko/20100101 Firefox/60.1", | ||
]; | ||
let info = null; | ||
console.log( | ||
`[blivec] DD ${id}`, | ||
interval > 0 ? `every ${interval} minutes` : "once" | ||
); | ||
while (info === null) { | ||
info = await getRoomPlayInfo(id).catch(() => null); | ||
if (info && !await testUrl(fst(info.streams).url, headers)) | ||
info = null; | ||
if (info || interval === 0) | ||
break; | ||
await setTimeout(interval * 60 * 1e3); | ||
async function poll() { | ||
let info = null; | ||
while (info === null) { | ||
info = await getRoomPlayInfo(id).catch(() => null); | ||
if (info && !await testUrl(fst(info.streams).url, headers)) | ||
info = null; | ||
if (info || interval === 0) | ||
break; | ||
await setTimeout(interval * 60 * 1e3); | ||
} | ||
function fst(obj) { | ||
for (const key in obj) | ||
return obj[key]; | ||
return {}; | ||
} | ||
return info; | ||
} | ||
function fst(obj) { | ||
for (const key in obj) | ||
return obj[key]; | ||
return {}; | ||
} | ||
if (info === null) { | ||
return; | ||
} | ||
const { title, streams } = info; | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
console.log("[blivec] Title:", title); | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
console.log("[blivec] Available streams:"); | ||
const names = Object.keys(streams); | ||
names.forEach((name, index) => { | ||
console.log(` ${index + 1}: ${name}`); | ||
}); | ||
const input = rl.createInterface({ | ||
input: process.stdin, | ||
output: process.stdout | ||
}); | ||
const choices = Array.from({ length: names.length }, (_, i2) => i2 + 1); | ||
const hint = [...choices, "Y=1", "max", "n"].join("/"); | ||
const choice = await new Promise((resolve) => { | ||
input.question(`[blivec] Choose a stream, or give up: (${hint}) `, (a) => { | ||
input.close(); | ||
resolve(a || "Y"); | ||
async function ask(info) { | ||
const { title, streams } = info; | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
console.log("[blivec] Title:", title); | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
console.log("[blivec] Available streams:"); | ||
const names = Object.keys(streams); | ||
const width = names.length > 9 ? 2 : 1; | ||
names.forEach((name, index) => { | ||
console.log(` ${String(index + 1).padStart(width)}: ${name}`); | ||
}); | ||
}); | ||
const i = Number.parseInt(choice); | ||
let selected = names[0]; | ||
if (Number.isSafeInteger(i) && 1 <= i && i <= names.length) { | ||
selected = names[i - 1]; | ||
} else { | ||
const a = choice[0].toLowerCase(); | ||
if (a === "n") { | ||
return; | ||
} else if (a === "m") { | ||
selected = names.reduce( | ||
(a2, b) => streams[a2].qn > streams[b].qn ? a2 : b | ||
const input = rl.createInterface({ | ||
input: process.stdin, | ||
output: process.stdout | ||
}); | ||
const choices = Array.from({ length: names.length }, (_, i2) => i2 + 1); | ||
const hint = [...choices, "Y=1", "max", "n"].join("/"); | ||
const choice = await new Promise((resolve) => { | ||
input.question( | ||
`[blivec] Choose a stream, or give up: (${hint}) `, | ||
(a) => { | ||
input.close(); | ||
resolve(a || "Y"); | ||
} | ||
); | ||
}); | ||
const i = Number.parseInt(choice); | ||
let selected2 = names[0]; | ||
if (Number.isSafeInteger(i) && 1 <= i && i <= names.length) { | ||
selected2 = names[i - 1]; | ||
} else { | ||
const a = choice[0].toLowerCase(); | ||
if (a === "n") { | ||
return; | ||
} else if (a === "m") { | ||
selected2 = names.reduce( | ||
(a2, b) => streams[a2].qn > streams[b].qn ? a2 : b | ||
); | ||
} | ||
} | ||
return selected2; | ||
} | ||
console.log("[blivec] Now playing:", `[${selected}] ${title}`); | ||
const url = streams[selected].url; | ||
let child; | ||
if (mpv) { | ||
const args = ["--quiet"]; | ||
args.push("--http-header-fields=" + headers.join(",")); | ||
args.push("--title=" + title); | ||
args.push("--geometry=50%"); | ||
args.push(url); | ||
child = cp.spawn("mpv", args, { stdio: "inherit", detached: true }); | ||
child.unref(); | ||
} else { | ||
const args = ["-hide_banner", "-loglevel", "error"]; | ||
args.push("-headers", headers.map((e) => e + "\r\n").join("")); | ||
args.push("-window_title", title); | ||
args.push("-x", "1280", "-y", "720"); | ||
args.push(url); | ||
child = cp.spawn("ffplay", args, { stdio: "inherit" }); | ||
function play(url, title) { | ||
let child2; | ||
if (mpv) { | ||
const args = ["--quiet"]; | ||
args.push("--http-header-fields=" + headers.join(",")); | ||
args.push("--title=" + title); | ||
args.push("--geometry=50%"); | ||
args.push(url); | ||
child2 = cp.spawn("mpv", args, { stdio: "inherit", detached: true }); | ||
child2.unref(); | ||
} else { | ||
const args = ["-hide_banner", "-loglevel", "error"]; | ||
args.push("-headers", headers.map((e) => e + "\r\n").join("")); | ||
args.push("-window_title", title); | ||
args.push("-x", "1280", "-y", "720"); | ||
args.push(url); | ||
child2 = cp.spawn("ffplay", args, { stdio: "inherit" }); | ||
} | ||
return child2; | ||
} | ||
const con = listen(id); | ||
child.once("exit", () => con.close()); | ||
let selected; | ||
async function replay() { | ||
const info = await poll(); | ||
if (!info) | ||
return; | ||
const { title } = info; | ||
selected ||= await ask(info); | ||
if (!selected) | ||
return; | ||
console.log("[blivec] Now playing:", `[${selected}] ${title}`); | ||
child = play(info.streams[selected].url, title); | ||
con ||= listen(id); | ||
con.resume(); | ||
child.on("exit", () => { | ||
con.pause(); | ||
setTimeout(100).then(replay); | ||
}); | ||
} | ||
await replay(); | ||
const quit = con.events.quit; | ||
con.events.quit = () => { | ||
quit && quit(); | ||
if (process.platform === "win32") { | ||
cp.execSync("taskkill /pid " + child.pid + " /T /F"); | ||
} else { | ||
process.kill(-child.pid, "SIGTERM"); | ||
} | ||
}; | ||
return con; | ||
@@ -256,3 +322,3 @@ } | ||
else | ||
console.log("\n[blivec] closing..."); | ||
console.log("[blivec] closing..."); | ||
con.close(); | ||
@@ -259,0 +325,0 @@ }); |
@@ -55,2 +55,17 @@ "use strict"; | ||
timer_heartbeat = /* @__PURE__ */ setTimeout(noop); | ||
_temp = null; | ||
pause() { | ||
this._temp || (this._temp = []); | ||
(this.events.pause || noop)(); | ||
} | ||
resume() { | ||
(this.events.resume || noop)(); | ||
const temp = this._temp; | ||
if (temp) { | ||
this._temp = null; | ||
for (const data of temp) { | ||
(this.events.message || noop)(data); | ||
} | ||
} | ||
} | ||
_closed = false; | ||
@@ -70,3 +85,7 @@ _connect_index = 0; | ||
this.buffer = EMPTY_BUFFER; | ||
const socket = await this.connect(); | ||
const socket = await this.connect().catch(() => null); | ||
if (socket === null) { | ||
this._on_close(); | ||
return; | ||
} | ||
this.socket = socket; | ||
@@ -105,2 +124,3 @@ this.timer_reconnect = setTimeout(this.reconnect.bind(this), 45e3); | ||
(this.events.error || noop)(err); | ||
this.socket = null; | ||
} | ||
@@ -133,3 +153,7 @@ _on_data(buffer) { | ||
} else if (type === "message") { | ||
(this.events.message || noop)(data); | ||
if (this._temp) { | ||
this._temp.push(data); | ||
} else { | ||
(this.events.message || noop)(data); | ||
} | ||
} | ||
@@ -136,0 +160,0 @@ } |
{ | ||
"name": "@hyrious/blivec", | ||
"version": "0.3.3", | ||
"version": "0.3.4", | ||
"description": "bilibili live cli", | ||
@@ -5,0 +5,0 @@ "type": "module", |
254
src/bin.ts
#!/usr/bin/env node | ||
import os from "os"; | ||
import fs from "fs"; | ||
import tty from "tty"; | ||
import { join } from "path"; | ||
@@ -30,2 +31,4 @@ import rl from "readline"; | ||
const hasColors = tty.WriteStream.prototype.hasColors(); | ||
function help() { | ||
@@ -35,2 +38,25 @@ console.log(help_text); | ||
function format(beg: number, end: number) { | ||
return hasColors | ||
? (str: any) => "\x1B[" + beg + "m" + str + "\x1B[" + end + "m" | ||
: (str: any) => str; | ||
} | ||
const red = format(31, 39); | ||
const cyan = format(36, 39); | ||
const black = format(30, 39); | ||
const bgRed = format(41, 49); | ||
function print_error(msg: string) { | ||
console.error(`${bgRed(black("\u2009ERROR\u2009"))} ${red(msg)}`); | ||
} | ||
function print_info(msg: string) { | ||
console.error(`${cyan("\u2009INFO\u2009")} ${cyan(msg)}`); | ||
} | ||
function error_exit(error: Error): never { | ||
print_error(error.message); | ||
process.exit(1); | ||
} | ||
function listen(id: number, { json = false } = {}) { | ||
@@ -40,3 +66,3 @@ let repl: rl.Interface | undefined; | ||
function setup_repl() { | ||
if (process.stdout.isTTY) { | ||
if (process.stdout.isTTY && !repl) { | ||
console.log('[blivec] type "> message" to send danmaku'); | ||
@@ -54,3 +80,5 @@ repl = rl.createInterface({ | ||
line = line.slice(2); | ||
send(id, line).catch(console.error); | ||
send(id, line).catch((error: Error) => { | ||
print_error(error.message); | ||
}); | ||
} else { | ||
@@ -69,2 +97,3 @@ console.log( | ||
let first = 0; | ||
const events: Events = json | ||
@@ -74,13 +103,18 @@ ? { | ||
message: (data) => console.log(JSON.stringify(data)), | ||
error: console.error, | ||
error: (err) => print_error(err.message), | ||
} | ||
: { | ||
init({ title, live_status, live_start_time }) { | ||
if (live_status === 1) { | ||
const time = new Date(live_start_time * 1000).toLocaleString(); | ||
console.log(`[blivec] listening ${title} (start at ${time})`); | ||
if (first === 0) { | ||
if (live_status === 1) { | ||
const time = new Date(live_start_time * 1000).toLocaleString(); | ||
console.log(`[blivec] listening ${title} (start at ${time})`); | ||
} else { | ||
console.log(`[blivec] listening ${title} (offline)`); | ||
} | ||
setup_repl(); | ||
} else { | ||
console.log(`[blivec] listening ${title} (offline)`); | ||
print_info(`reconnected (x${first})`); | ||
} | ||
setup_repl(); | ||
first++; | ||
}, | ||
@@ -94,4 +128,6 @@ message(a) { | ||
}, | ||
error: console.error, | ||
error: (err) => print_error(err.message), | ||
quit: () => repl && repl.close(), | ||
pause: () => repl && repl.pause(), | ||
resume: () => repl && repl.resume(), | ||
}; | ||
@@ -104,7 +140,7 @@ | ||
function example() { | ||
console.log("Example content:"); | ||
console.log(""); | ||
console.log("SESSDATA=..."); | ||
console.log("bili_jct=..."); | ||
console.log(); | ||
console.error("Example content:"); | ||
console.error(""); | ||
console.error("SESSDATA=..."); | ||
console.error("bili_jct=..."); | ||
console.error(); | ||
} | ||
@@ -124,3 +160,3 @@ | ||
if (!path) { | ||
console.log('Please create a file "cookie.txt" in current directory.'); | ||
console.error('Please create a file "cookie.txt" in current directory.'); | ||
example(); | ||
@@ -142,5 +178,7 @@ process.exit(1); | ||
if (env.SESSDATA && env.bili_jct) { | ||
await sendDanmaku(id, message, env).catch(console.error); | ||
await sendDanmaku(id, message, env).catch((err) => { | ||
print_error(err.message); | ||
}); | ||
} else { | ||
console.log("Invalid cookie.txt"); | ||
print_error("Invalid cookie.txt"); | ||
example(); | ||
@@ -170,4 +208,3 @@ process.exit(1); | ||
} catch (err: any) { | ||
console.error("Error:", err.message); | ||
process.exit(1); | ||
error_exit(err); | ||
} | ||
@@ -177,2 +214,10 @@ } | ||
async function D(id: number, { interval = 1, mpv = false } = {}) { | ||
console.log( | ||
`[blivec] DD ${id}`, | ||
interval > 0 ? `every ${interval} minutes` : "once" | ||
); | ||
let con!: Connection; | ||
let child!: cp.ChildProcess; | ||
const headers = [ | ||
@@ -184,82 +229,113 @@ "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.1) Gecko/20100101 Firefox/60.1", | ||
type RoomPlayInfo = Awaited<ReturnType<typeof getRoomPlayInfo>>; | ||
let info: RoomPlayInfo | null = null; | ||
console.log( | ||
`[blivec] DD ${id}`, | ||
interval > 0 ? `every ${interval} minutes` : "once" | ||
); | ||
while (info === null) { | ||
info = await getRoomPlayInfo(id).catch(() => null); | ||
if (info && !(await testUrl(fst(info.streams).url, headers))) info = null; | ||
if (info || interval === 0) break; | ||
await setTimeout(interval * 60 * 1000); | ||
async function poll() { | ||
let info: RoomPlayInfo | null = null; | ||
while (info === null) { | ||
info = await getRoomPlayInfo(id).catch(() => null); | ||
if (info && !(await testUrl(fst(info.streams).url, headers))) info = null; | ||
if (info || interval === 0) break; | ||
await setTimeout(interval * 60 * 1000); | ||
} | ||
function fst<T extends {}>(obj: T): T[keyof T] { | ||
for (const key in obj) return obj[key]; | ||
return {} as any; | ||
} | ||
return info; | ||
} | ||
function fst<T extends {}>(obj: T): T[keyof T] { | ||
for (const key in obj) return obj[key]; | ||
return {} as any; | ||
} | ||
if (info === null) { | ||
return; | ||
} | ||
async function ask(info: RoomPlayInfo) { | ||
const { title, streams } = info; | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
console.log("[blivec] Title:", title); | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
const { title, streams } = info; | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
console.log("[blivec] Title:", title); | ||
console.log("[blivec] " + "=====".repeat(10)); | ||
console.log("[blivec] Available streams:"); | ||
const names = Object.keys(streams); | ||
names.forEach((name, index) => { | ||
console.log(` ${index + 1}: ${name}`); | ||
}); | ||
const input = rl.createInterface({ | ||
input: process.stdin, | ||
output: process.stdout, | ||
}); | ||
const choices = Array.from({ length: names.length }, (_, i) => i + 1); | ||
const hint = [...choices, "Y=1", "max", "n"].join("/"); | ||
const choice = await new Promise<string>((resolve) => { | ||
input.question(`[blivec] Choose a stream, or give up: (${hint}) `, (a) => { | ||
input.close(); | ||
resolve(a || "Y"); | ||
console.log("[blivec] Available streams:"); | ||
const names = Object.keys(streams); | ||
const width = names.length > 9 ? 2 : 1; | ||
names.forEach((name, index) => { | ||
console.log(` ${String(index + 1).padStart(width)}: ${name}`); | ||
}); | ||
}); | ||
const i = Number.parseInt(choice); | ||
let selected = names[0]; | ||
if (Number.isSafeInteger(i) && 1 <= i && i <= names.length) { | ||
selected = names[i - 1]; | ||
} else { | ||
const a = choice[0].toLowerCase(); | ||
if (a === "n") { | ||
return; | ||
} else if (a === "m") { | ||
selected = names.reduce((a, b) => | ||
streams[a].qn > streams[b].qn ? a : b | ||
const input = rl.createInterface({ | ||
input: process.stdin, | ||
output: process.stdout, | ||
}); | ||
const choices = Array.from({ length: names.length }, (_, i) => i + 1); | ||
const hint = [...choices, "Y=1", "max", "n"].join("/"); | ||
const choice = await new Promise<string>((resolve) => { | ||
input.question( | ||
`[blivec] Choose a stream, or give up: (${hint}) `, | ||
(a) => { | ||
input.close(); | ||
resolve(a || "Y"); | ||
} | ||
); | ||
}); | ||
const i = Number.parseInt(choice); | ||
let selected = names[0]; | ||
if (Number.isSafeInteger(i) && 1 <= i && i <= names.length) { | ||
selected = names[i - 1]; | ||
} else { | ||
const a = choice[0].toLowerCase(); | ||
if (a === "n") { | ||
return; | ||
} else if (a === "m") { | ||
selected = names.reduce((a, b) => | ||
streams[a].qn > streams[b].qn ? a : b | ||
); | ||
} | ||
} | ||
return selected; | ||
} | ||
console.log("[blivec] Now playing:", `[${selected}] ${title}`); | ||
const url = streams[selected].url; | ||
function play(url: string, title: string) { | ||
let child: ChildProcess; | ||
if (mpv) { | ||
const args = ["--quiet"]; | ||
args.push("--http-header-fields=" + headers.join(",")); | ||
args.push("--title=" + title); | ||
args.push("--geometry=50%"); | ||
args.push(url); | ||
child = cp.spawn("mpv", args, { stdio: "inherit", detached: true }); | ||
child.unref(); | ||
} else { | ||
const args = ["-hide_banner", "-loglevel", "error"]; | ||
args.push("-headers", headers.map((e) => e + "\r\n").join("")); | ||
args.push("-window_title", title); | ||
args.push("-x", "1280", "-y", "720"); | ||
args.push(url); | ||
child = cp.spawn("ffplay", args, { stdio: "inherit" }); | ||
} | ||
return child; | ||
} | ||
let child: ChildProcess; | ||
if (mpv) { | ||
const args = ["--quiet"]; | ||
args.push("--http-header-fields=" + headers.join(",")); | ||
args.push("--title=" + title); | ||
args.push("--geometry=50%"); | ||
args.push(url); | ||
child = cp.spawn("mpv", args, { stdio: "inherit", detached: true }); | ||
child.unref(); | ||
} else { | ||
const args = ["-hide_banner", "-loglevel", "error"]; | ||
args.push("-headers", headers.map((e) => e + "\r\n").join("")); | ||
args.push("-window_title", title); | ||
args.push("-x", "1280", "-y", "720"); | ||
args.push(url); | ||
child = cp.spawn("ffplay", args, { stdio: "inherit" }); | ||
let selected: string | undefined; | ||
async function replay() { | ||
const info = await poll(); | ||
if (!info) return; | ||
const { title } = info; | ||
selected ||= await ask(info); | ||
if (!selected) return; | ||
console.log("[blivec] Now playing:", `[${selected}] ${title}`); | ||
child = play(info.streams[selected].url, title); | ||
con ||= listen(id); | ||
con.resume(); | ||
child.on("exit", () => { | ||
con.pause(); | ||
setTimeout(100).then(replay); | ||
}); | ||
} | ||
const con = listen(id); | ||
child.once("exit", () => con.close()); | ||
await replay(); | ||
const quit = con.events.quit; | ||
con.events.quit = () => { | ||
quit && quit(); | ||
if (process.platform === "win32") { | ||
cp.execSync("taskkill /pid " + child.pid + " /T /F"); | ||
} else { | ||
process.kill(-child.pid!, "SIGTERM"); | ||
} | ||
}; | ||
return con; | ||
@@ -275,3 +351,3 @@ } | ||
if (json) console.log(JSON.stringify({ cmd: "exit" })); | ||
else console.log("\n[blivec] closing..."); | ||
else console.log("[blivec] closing..."); | ||
con.close(); | ||
@@ -278,0 +354,0 @@ }); |
@@ -72,4 +72,6 @@ import https from "https"; | ||
message?: (data: any) => void; | ||
error?: (err: any) => void; | ||
error?: (err: Error) => void; | ||
quit?: () => void; | ||
pause?: () => void; | ||
resume?: () => void; | ||
} | ||
@@ -89,2 +91,18 @@ | ||
_temp: any[] | null = null; | ||
pause() { | ||
this._temp || (this._temp = []); | ||
(this.events.pause || noop)(); | ||
} | ||
resume() { | ||
(this.events.resume || noop)(); | ||
const temp = this._temp; | ||
if (temp) { | ||
this._temp = null; | ||
for (const data of temp) { | ||
(this.events.message || noop)(data); | ||
} | ||
} | ||
} | ||
_closed = false; | ||
@@ -108,3 +126,7 @@ _connect_index = 0; | ||
const socket = await this.connect(); | ||
const socket = await this.connect().catch(() => null); | ||
if (socket === null) { | ||
this._on_close(); | ||
return; | ||
} | ||
this.socket = socket; | ||
@@ -146,4 +168,5 @@ this.timer_reconnect = setTimeout(this.reconnect.bind(this), 45e3); | ||
_on_error(err: any) { | ||
_on_error(err: Error) { | ||
(this.events.error || noop)(err); | ||
this.socket = null; | ||
} | ||
@@ -180,3 +203,7 @@ | ||
} else if (type === "message") { | ||
(this.events.message || noop)(data); | ||
if (this._temp) { | ||
this._temp.push(data); | ||
} else { | ||
(this.events.message || noop)(data); | ||
} | ||
} | ||
@@ -183,0 +210,0 @@ } |
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
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
58129
9
1755