bililive-cli 3.13.1 → 3.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,18 +4,18 @@ var path$7 = require('node:path');
|
|
|
4
4
|
var require$$2$1 = require('node:http');
|
|
5
5
|
var require$$1$2 = require('node:url');
|
|
6
6
|
var a = require('node:https');
|
|
7
|
-
var index = require('./index-
|
|
8
|
-
var require$$0$
|
|
9
|
-
var require$$1$
|
|
7
|
+
var index = require('./index-EjlRQsb6.cjs');
|
|
8
|
+
var require$$0$5 = require('tty');
|
|
9
|
+
var require$$1$4 = require('util');
|
|
10
10
|
var require$$0$b = require('assert');
|
|
11
|
-
var require$$0$
|
|
12
|
-
var require$$0$
|
|
13
|
-
var require$$0$
|
|
11
|
+
var require$$0$7 = require('path');
|
|
12
|
+
var require$$0$6 = require('buffer');
|
|
13
|
+
var require$$0$4 = require('events');
|
|
14
14
|
var require$$0$8 = require('fs');
|
|
15
15
|
var require$$0$9 = require('stream');
|
|
16
16
|
var zlib$1 = require('zlib');
|
|
17
17
|
var require$$0$a = require('url');
|
|
18
|
-
var require$$1$
|
|
18
|
+
var require$$1$3 = require('crypto');
|
|
19
19
|
var require$$3$1 = require('http');
|
|
20
20
|
var require$$0$c = require('net');
|
|
21
21
|
var require$$5$1 = require('querystring');
|
|
@@ -25,7 +25,7 @@ var os$1 = require('node:os');
|
|
|
25
25
|
var require$$1$6 = require('os');
|
|
26
26
|
var require$$1$1 = require('node:child_process');
|
|
27
27
|
var fs$6 = require('node:fs');
|
|
28
|
-
var EventEmitter$
|
|
28
|
+
var EventEmitter$4 = require('node:events');
|
|
29
29
|
require('ntsuspend');
|
|
30
30
|
require('node:crypto');
|
|
31
31
|
require('node:readline');
|
|
@@ -48,13 +48,13 @@ require('vm');
|
|
|
48
48
|
require('node:stream');
|
|
49
49
|
require('node:stream/promises');
|
|
50
50
|
require('fs/promises');
|
|
51
|
-
require('node:net');
|
|
52
|
-
require('node:zlib');
|
|
53
51
|
require('node:assert');
|
|
52
|
+
require('node:net');
|
|
54
53
|
require('node:querystring');
|
|
55
54
|
require('node:diagnostics_channel');
|
|
56
55
|
require('node:tls');
|
|
57
56
|
require('node:buffer');
|
|
57
|
+
require('node:zlib');
|
|
58
58
|
require('node:perf_hooks');
|
|
59
59
|
require('node:util/types');
|
|
60
60
|
require('node:sqlite');
|
|
@@ -1504,6 +1504,607 @@ class LocalCopy extends index.TypedEmitter {
|
|
|
1504
1504
|
}
|
|
1505
1505
|
}
|
|
1506
1506
|
|
|
1507
|
+
const { tokenChars } = index.validationExports;
|
|
1508
|
+
|
|
1509
|
+
/**
|
|
1510
|
+
* Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
|
|
1511
|
+
*
|
|
1512
|
+
* @param {String} header The field value of the header
|
|
1513
|
+
* @return {Set} The subprotocol names
|
|
1514
|
+
* @public
|
|
1515
|
+
*/
|
|
1516
|
+
function parse$l(header) {
|
|
1517
|
+
const protocols = new Set();
|
|
1518
|
+
let start = -1;
|
|
1519
|
+
let end = -1;
|
|
1520
|
+
let i = 0;
|
|
1521
|
+
|
|
1522
|
+
for (i; i < header.length; i++) {
|
|
1523
|
+
const code = header.charCodeAt(i);
|
|
1524
|
+
|
|
1525
|
+
if (end === -1 && tokenChars[code] === 1) {
|
|
1526
|
+
if (start === -1) start = i;
|
|
1527
|
+
} else if (
|
|
1528
|
+
i !== 0 &&
|
|
1529
|
+
(code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
|
|
1530
|
+
) {
|
|
1531
|
+
if (end === -1 && start !== -1) end = i;
|
|
1532
|
+
} else if (code === 0x2c /* ',' */) {
|
|
1533
|
+
if (start === -1) {
|
|
1534
|
+
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
if (end === -1) end = i;
|
|
1538
|
+
|
|
1539
|
+
const protocol = header.slice(start, end);
|
|
1540
|
+
|
|
1541
|
+
if (protocols.has(protocol)) {
|
|
1542
|
+
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
protocols.add(protocol);
|
|
1546
|
+
start = end = -1;
|
|
1547
|
+
} else {
|
|
1548
|
+
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
if (start === -1 || end !== -1) {
|
|
1553
|
+
throw new SyntaxError('Unexpected end of input');
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
const protocol = header.slice(start, i);
|
|
1557
|
+
|
|
1558
|
+
if (protocols.has(protocol)) {
|
|
1559
|
+
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
protocols.add(protocol);
|
|
1563
|
+
return protocols;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
var subprotocol$1 = { parse: parse$l };
|
|
1567
|
+
|
|
1568
|
+
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */
|
|
1569
|
+
|
|
1570
|
+
const EventEmitter$3 = require$$0$4;
|
|
1571
|
+
const http$3 = require$$3$1;
|
|
1572
|
+
const { createHash } = require$$1$3;
|
|
1573
|
+
|
|
1574
|
+
const extension = index.extension;
|
|
1575
|
+
const PerMessageDeflate = index.permessageDeflate;
|
|
1576
|
+
const subprotocol = subprotocol$1;
|
|
1577
|
+
const WebSocket = index.websocket;
|
|
1578
|
+
const { GUID, kWebSocket } = index.constants;
|
|
1579
|
+
|
|
1580
|
+
const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
|
|
1581
|
+
|
|
1582
|
+
const RUNNING = 0;
|
|
1583
|
+
const CLOSING = 1;
|
|
1584
|
+
const CLOSED = 2;
|
|
1585
|
+
|
|
1586
|
+
/**
|
|
1587
|
+
* Class representing a WebSocket server.
|
|
1588
|
+
*
|
|
1589
|
+
* @extends EventEmitter
|
|
1590
|
+
*/
|
|
1591
|
+
class WebSocketServer extends EventEmitter$3 {
|
|
1592
|
+
/**
|
|
1593
|
+
* Create a `WebSocketServer` instance.
|
|
1594
|
+
*
|
|
1595
|
+
* @param {Object} options Configuration options
|
|
1596
|
+
* @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
|
|
1597
|
+
* any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
|
|
1598
|
+
* multiple times in the same tick
|
|
1599
|
+
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
|
|
1600
|
+
* automatically send a pong in response to a ping
|
|
1601
|
+
* @param {Number} [options.backlog=511] The maximum length of the queue of
|
|
1602
|
+
* pending connections
|
|
1603
|
+
* @param {Boolean} [options.clientTracking=true] Specifies whether or not to
|
|
1604
|
+
* track clients
|
|
1605
|
+
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
1606
|
+
* @param {String} [options.host] The hostname where to bind the server
|
|
1607
|
+
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
1608
|
+
* size
|
|
1609
|
+
* @param {Boolean} [options.noServer=false] Enable no server mode
|
|
1610
|
+
* @param {String} [options.path] Accept only connections matching this path
|
|
1611
|
+
* @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
|
|
1612
|
+
* permessage-deflate
|
|
1613
|
+
* @param {Number} [options.port] The port where to bind the server
|
|
1614
|
+
* @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
|
|
1615
|
+
* server to use
|
|
1616
|
+
* @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
|
|
1617
|
+
* not to skip UTF-8 validation for text and close messages
|
|
1618
|
+
* @param {Function} [options.verifyClient] A hook to reject connections
|
|
1619
|
+
* @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
|
|
1620
|
+
* class to use. It must be the `WebSocket` class or class that extends it
|
|
1621
|
+
* @param {Function} [callback] A listener for the `listening` event
|
|
1622
|
+
*/
|
|
1623
|
+
constructor(options, callback) {
|
|
1624
|
+
super();
|
|
1625
|
+
|
|
1626
|
+
options = {
|
|
1627
|
+
allowSynchronousEvents: true,
|
|
1628
|
+
autoPong: true,
|
|
1629
|
+
maxPayload: 100 * 1024 * 1024,
|
|
1630
|
+
skipUTF8Validation: false,
|
|
1631
|
+
perMessageDeflate: false,
|
|
1632
|
+
handleProtocols: null,
|
|
1633
|
+
clientTracking: true,
|
|
1634
|
+
verifyClient: null,
|
|
1635
|
+
noServer: false,
|
|
1636
|
+
backlog: null, // use default (511 as implemented in net.js)
|
|
1637
|
+
server: null,
|
|
1638
|
+
host: null,
|
|
1639
|
+
path: null,
|
|
1640
|
+
port: null,
|
|
1641
|
+
WebSocket,
|
|
1642
|
+
...options
|
|
1643
|
+
};
|
|
1644
|
+
|
|
1645
|
+
if (
|
|
1646
|
+
(options.port == null && !options.server && !options.noServer) ||
|
|
1647
|
+
(options.port != null && (options.server || options.noServer)) ||
|
|
1648
|
+
(options.server && options.noServer)
|
|
1649
|
+
) {
|
|
1650
|
+
throw new TypeError(
|
|
1651
|
+
'One and only one of the "port", "server", or "noServer" options ' +
|
|
1652
|
+
'must be specified'
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
if (options.port != null) {
|
|
1657
|
+
this._server = http$3.createServer((req, res) => {
|
|
1658
|
+
const body = http$3.STATUS_CODES[426];
|
|
1659
|
+
|
|
1660
|
+
res.writeHead(426, {
|
|
1661
|
+
'Content-Length': body.length,
|
|
1662
|
+
'Content-Type': 'text/plain'
|
|
1663
|
+
});
|
|
1664
|
+
res.end(body);
|
|
1665
|
+
});
|
|
1666
|
+
this._server.listen(
|
|
1667
|
+
options.port,
|
|
1668
|
+
options.host,
|
|
1669
|
+
options.backlog,
|
|
1670
|
+
callback
|
|
1671
|
+
);
|
|
1672
|
+
} else if (options.server) {
|
|
1673
|
+
this._server = options.server;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
if (this._server) {
|
|
1677
|
+
const emitConnection = this.emit.bind(this, 'connection');
|
|
1678
|
+
|
|
1679
|
+
this._removeListeners = addListeners(this._server, {
|
|
1680
|
+
listening: this.emit.bind(this, 'listening'),
|
|
1681
|
+
error: this.emit.bind(this, 'error'),
|
|
1682
|
+
upgrade: (req, socket, head) => {
|
|
1683
|
+
this.handleUpgrade(req, socket, head, emitConnection);
|
|
1684
|
+
}
|
|
1685
|
+
});
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
if (options.perMessageDeflate === true) options.perMessageDeflate = {};
|
|
1689
|
+
if (options.clientTracking) {
|
|
1690
|
+
this.clients = new Set();
|
|
1691
|
+
this._shouldEmitClose = false;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
this.options = options;
|
|
1695
|
+
this._state = RUNNING;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
/**
|
|
1699
|
+
* Returns the bound address, the address family name, and port of the server
|
|
1700
|
+
* as reported by the operating system if listening on an IP socket.
|
|
1701
|
+
* If the server is listening on a pipe or UNIX domain socket, the name is
|
|
1702
|
+
* returned as a string.
|
|
1703
|
+
*
|
|
1704
|
+
* @return {(Object|String|null)} The address of the server
|
|
1705
|
+
* @public
|
|
1706
|
+
*/
|
|
1707
|
+
address() {
|
|
1708
|
+
if (this.options.noServer) {
|
|
1709
|
+
throw new Error('The server is operating in "noServer" mode');
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
if (!this._server) return null;
|
|
1713
|
+
return this._server.address();
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
/**
|
|
1717
|
+
* Stop the server from accepting new connections and emit the `'close'` event
|
|
1718
|
+
* when all existing connections are closed.
|
|
1719
|
+
*
|
|
1720
|
+
* @param {Function} [cb] A one-time listener for the `'close'` event
|
|
1721
|
+
* @public
|
|
1722
|
+
*/
|
|
1723
|
+
close(cb) {
|
|
1724
|
+
if (this._state === CLOSED) {
|
|
1725
|
+
if (cb) {
|
|
1726
|
+
this.once('close', () => {
|
|
1727
|
+
cb(new Error('The server is not running'));
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
process.nextTick(emitClose, this);
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
if (cb) this.once('close', cb);
|
|
1736
|
+
|
|
1737
|
+
if (this._state === CLOSING) return;
|
|
1738
|
+
this._state = CLOSING;
|
|
1739
|
+
|
|
1740
|
+
if (this.options.noServer || this.options.server) {
|
|
1741
|
+
if (this._server) {
|
|
1742
|
+
this._removeListeners();
|
|
1743
|
+
this._removeListeners = this._server = null;
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
if (this.clients) {
|
|
1747
|
+
if (!this.clients.size) {
|
|
1748
|
+
process.nextTick(emitClose, this);
|
|
1749
|
+
} else {
|
|
1750
|
+
this._shouldEmitClose = true;
|
|
1751
|
+
}
|
|
1752
|
+
} else {
|
|
1753
|
+
process.nextTick(emitClose, this);
|
|
1754
|
+
}
|
|
1755
|
+
} else {
|
|
1756
|
+
const server = this._server;
|
|
1757
|
+
|
|
1758
|
+
this._removeListeners();
|
|
1759
|
+
this._removeListeners = this._server = null;
|
|
1760
|
+
|
|
1761
|
+
//
|
|
1762
|
+
// The HTTP/S server was created internally. Close it, and rely on its
|
|
1763
|
+
// `'close'` event.
|
|
1764
|
+
//
|
|
1765
|
+
server.close(() => {
|
|
1766
|
+
emitClose(this);
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
/**
|
|
1772
|
+
* See if a given request should be handled by this server instance.
|
|
1773
|
+
*
|
|
1774
|
+
* @param {http.IncomingMessage} req Request object to inspect
|
|
1775
|
+
* @return {Boolean} `true` if the request is valid, else `false`
|
|
1776
|
+
* @public
|
|
1777
|
+
*/
|
|
1778
|
+
shouldHandle(req) {
|
|
1779
|
+
if (this.options.path) {
|
|
1780
|
+
const index = req.url.indexOf('?');
|
|
1781
|
+
const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
|
|
1782
|
+
|
|
1783
|
+
if (pathname !== this.options.path) return false;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
return true;
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
/**
|
|
1790
|
+
* Handle a HTTP Upgrade request.
|
|
1791
|
+
*
|
|
1792
|
+
* @param {http.IncomingMessage} req The request object
|
|
1793
|
+
* @param {Duplex} socket The network socket between the server and client
|
|
1794
|
+
* @param {Buffer} head The first packet of the upgraded stream
|
|
1795
|
+
* @param {Function} cb Callback
|
|
1796
|
+
* @public
|
|
1797
|
+
*/
|
|
1798
|
+
handleUpgrade(req, socket, head, cb) {
|
|
1799
|
+
socket.on('error', socketOnError);
|
|
1800
|
+
|
|
1801
|
+
const key = req.headers['sec-websocket-key'];
|
|
1802
|
+
const upgrade = req.headers.upgrade;
|
|
1803
|
+
const version = +req.headers['sec-websocket-version'];
|
|
1804
|
+
|
|
1805
|
+
if (req.method !== 'GET') {
|
|
1806
|
+
const message = 'Invalid HTTP method';
|
|
1807
|
+
abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
|
|
1812
|
+
const message = 'Invalid Upgrade header';
|
|
1813
|
+
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
if (key === undefined || !keyRegex.test(key)) {
|
|
1818
|
+
const message = 'Missing or invalid Sec-WebSocket-Key header';
|
|
1819
|
+
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
1820
|
+
return;
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
if (version !== 8 && version !== 13) {
|
|
1824
|
+
const message = 'Missing or invalid Sec-WebSocket-Version header';
|
|
1825
|
+
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
if (!this.shouldHandle(req)) {
|
|
1830
|
+
abortHandshake(socket, 400);
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
const secWebSocketProtocol = req.headers['sec-websocket-protocol'];
|
|
1835
|
+
let protocols = new Set();
|
|
1836
|
+
|
|
1837
|
+
if (secWebSocketProtocol !== undefined) {
|
|
1838
|
+
try {
|
|
1839
|
+
protocols = subprotocol.parse(secWebSocketProtocol);
|
|
1840
|
+
} catch (err) {
|
|
1841
|
+
const message = 'Invalid Sec-WebSocket-Protocol header';
|
|
1842
|
+
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
const secWebSocketExtensions = req.headers['sec-websocket-extensions'];
|
|
1848
|
+
const extensions = {};
|
|
1849
|
+
|
|
1850
|
+
if (
|
|
1851
|
+
this.options.perMessageDeflate &&
|
|
1852
|
+
secWebSocketExtensions !== undefined
|
|
1853
|
+
) {
|
|
1854
|
+
const perMessageDeflate = new PerMessageDeflate(
|
|
1855
|
+
this.options.perMessageDeflate,
|
|
1856
|
+
true,
|
|
1857
|
+
this.options.maxPayload
|
|
1858
|
+
);
|
|
1859
|
+
|
|
1860
|
+
try {
|
|
1861
|
+
const offers = extension.parse(secWebSocketExtensions);
|
|
1862
|
+
|
|
1863
|
+
if (offers[PerMessageDeflate.extensionName]) {
|
|
1864
|
+
perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
|
|
1865
|
+
extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
|
|
1866
|
+
}
|
|
1867
|
+
} catch (err) {
|
|
1868
|
+
const message =
|
|
1869
|
+
'Invalid or unacceptable Sec-WebSocket-Extensions header';
|
|
1870
|
+
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
//
|
|
1876
|
+
// Optionally call external client verification handler.
|
|
1877
|
+
//
|
|
1878
|
+
if (this.options.verifyClient) {
|
|
1879
|
+
const info = {
|
|
1880
|
+
origin:
|
|
1881
|
+
req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
|
|
1882
|
+
secure: !!(req.socket.authorized || req.socket.encrypted),
|
|
1883
|
+
req
|
|
1884
|
+
};
|
|
1885
|
+
|
|
1886
|
+
if (this.options.verifyClient.length === 2) {
|
|
1887
|
+
this.options.verifyClient(info, (verified, code, message, headers) => {
|
|
1888
|
+
if (!verified) {
|
|
1889
|
+
return abortHandshake(socket, code || 401, message, headers);
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
this.completeUpgrade(
|
|
1893
|
+
extensions,
|
|
1894
|
+
key,
|
|
1895
|
+
protocols,
|
|
1896
|
+
req,
|
|
1897
|
+
socket,
|
|
1898
|
+
head,
|
|
1899
|
+
cb
|
|
1900
|
+
);
|
|
1901
|
+
});
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
/**
|
|
1912
|
+
* Upgrade the connection to WebSocket.
|
|
1913
|
+
*
|
|
1914
|
+
* @param {Object} extensions The accepted extensions
|
|
1915
|
+
* @param {String} key The value of the `Sec-WebSocket-Key` header
|
|
1916
|
+
* @param {Set} protocols The subprotocols
|
|
1917
|
+
* @param {http.IncomingMessage} req The request object
|
|
1918
|
+
* @param {Duplex} socket The network socket between the server and client
|
|
1919
|
+
* @param {Buffer} head The first packet of the upgraded stream
|
|
1920
|
+
* @param {Function} cb Callback
|
|
1921
|
+
* @throws {Error} If called more than once with the same socket
|
|
1922
|
+
* @private
|
|
1923
|
+
*/
|
|
1924
|
+
completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
|
|
1925
|
+
//
|
|
1926
|
+
// Destroy the socket if the client has already sent a FIN packet.
|
|
1927
|
+
//
|
|
1928
|
+
if (!socket.readable || !socket.writable) return socket.destroy();
|
|
1929
|
+
|
|
1930
|
+
if (socket[kWebSocket]) {
|
|
1931
|
+
throw new Error(
|
|
1932
|
+
'server.handleUpgrade() was called more than once with the same ' +
|
|
1933
|
+
'socket, possibly due to a misconfiguration'
|
|
1934
|
+
);
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
1938
|
+
|
|
1939
|
+
const digest = createHash('sha1')
|
|
1940
|
+
.update(key + GUID)
|
|
1941
|
+
.digest('base64');
|
|
1942
|
+
|
|
1943
|
+
const headers = [
|
|
1944
|
+
'HTTP/1.1 101 Switching Protocols',
|
|
1945
|
+
'Upgrade: websocket',
|
|
1946
|
+
'Connection: Upgrade',
|
|
1947
|
+
`Sec-WebSocket-Accept: ${digest}`
|
|
1948
|
+
];
|
|
1949
|
+
|
|
1950
|
+
const ws = new this.options.WebSocket(null, undefined, this.options);
|
|
1951
|
+
|
|
1952
|
+
if (protocols.size) {
|
|
1953
|
+
//
|
|
1954
|
+
// Optionally call external protocol selection handler.
|
|
1955
|
+
//
|
|
1956
|
+
const protocol = this.options.handleProtocols
|
|
1957
|
+
? this.options.handleProtocols(protocols, req)
|
|
1958
|
+
: protocols.values().next().value;
|
|
1959
|
+
|
|
1960
|
+
if (protocol) {
|
|
1961
|
+
headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
|
|
1962
|
+
ws._protocol = protocol;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
if (extensions[PerMessageDeflate.extensionName]) {
|
|
1967
|
+
const params = extensions[PerMessageDeflate.extensionName].params;
|
|
1968
|
+
const value = extension.format({
|
|
1969
|
+
[PerMessageDeflate.extensionName]: [params]
|
|
1970
|
+
});
|
|
1971
|
+
headers.push(`Sec-WebSocket-Extensions: ${value}`);
|
|
1972
|
+
ws._extensions = extensions;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
//
|
|
1976
|
+
// Allow external modification/inspection of handshake headers.
|
|
1977
|
+
//
|
|
1978
|
+
this.emit('headers', headers, req);
|
|
1979
|
+
|
|
1980
|
+
socket.write(headers.concat('\r\n').join('\r\n'));
|
|
1981
|
+
socket.removeListener('error', socketOnError);
|
|
1982
|
+
|
|
1983
|
+
ws.setSocket(socket, head, {
|
|
1984
|
+
allowSynchronousEvents: this.options.allowSynchronousEvents,
|
|
1985
|
+
maxPayload: this.options.maxPayload,
|
|
1986
|
+
skipUTF8Validation: this.options.skipUTF8Validation
|
|
1987
|
+
});
|
|
1988
|
+
|
|
1989
|
+
if (this.clients) {
|
|
1990
|
+
this.clients.add(ws);
|
|
1991
|
+
ws.on('close', () => {
|
|
1992
|
+
this.clients.delete(ws);
|
|
1993
|
+
|
|
1994
|
+
if (this._shouldEmitClose && !this.clients.size) {
|
|
1995
|
+
process.nextTick(emitClose, this);
|
|
1996
|
+
}
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
cb(ws, req);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
var websocketServer = WebSocketServer;
|
|
2005
|
+
|
|
2006
|
+
/**
|
|
2007
|
+
* Add event listeners on an `EventEmitter` using a map of <event, listener>
|
|
2008
|
+
* pairs.
|
|
2009
|
+
*
|
|
2010
|
+
* @param {EventEmitter} server The event emitter
|
|
2011
|
+
* @param {Object.<String, Function>} map The listeners to add
|
|
2012
|
+
* @return {Function} A function that will remove the added listeners when
|
|
2013
|
+
* called
|
|
2014
|
+
* @private
|
|
2015
|
+
*/
|
|
2016
|
+
function addListeners(server, map) {
|
|
2017
|
+
for (const event of Object.keys(map)) server.on(event, map[event]);
|
|
2018
|
+
|
|
2019
|
+
return function removeListeners() {
|
|
2020
|
+
for (const event of Object.keys(map)) {
|
|
2021
|
+
server.removeListener(event, map[event]);
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
/**
|
|
2027
|
+
* Emit a `'close'` event on an `EventEmitter`.
|
|
2028
|
+
*
|
|
2029
|
+
* @param {EventEmitter} server The event emitter
|
|
2030
|
+
* @private
|
|
2031
|
+
*/
|
|
2032
|
+
function emitClose(server) {
|
|
2033
|
+
server._state = CLOSED;
|
|
2034
|
+
server.emit('close');
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
/**
|
|
2038
|
+
* Handle socket errors.
|
|
2039
|
+
*
|
|
2040
|
+
* @private
|
|
2041
|
+
*/
|
|
2042
|
+
function socketOnError() {
|
|
2043
|
+
this.destroy();
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
/**
|
|
2047
|
+
* Close the connection when preconditions are not fulfilled.
|
|
2048
|
+
*
|
|
2049
|
+
* @param {Duplex} socket The socket of the upgrade request
|
|
2050
|
+
* @param {Number} code The HTTP response status code
|
|
2051
|
+
* @param {String} [message] The HTTP response body
|
|
2052
|
+
* @param {Object} [headers] Additional HTTP response headers
|
|
2053
|
+
* @private
|
|
2054
|
+
*/
|
|
2055
|
+
function abortHandshake(socket, code, message, headers) {
|
|
2056
|
+
//
|
|
2057
|
+
// The socket is writable unless the user destroyed or ended it before calling
|
|
2058
|
+
// `server.handleUpgrade()` or in the `verifyClient` function, which is a user
|
|
2059
|
+
// error. Handling this does not make much sense as the worst that can happen
|
|
2060
|
+
// is that some of the data written by the user might be discarded due to the
|
|
2061
|
+
// call to `socket.end()` below, which triggers an `'error'` event that in
|
|
2062
|
+
// turn causes the socket to be destroyed.
|
|
2063
|
+
//
|
|
2064
|
+
message = message || http$3.STATUS_CODES[code];
|
|
2065
|
+
headers = {
|
|
2066
|
+
Connection: 'close',
|
|
2067
|
+
'Content-Type': 'text/html',
|
|
2068
|
+
'Content-Length': Buffer.byteLength(message),
|
|
2069
|
+
...headers
|
|
2070
|
+
};
|
|
2071
|
+
|
|
2072
|
+
socket.once('finish', socket.destroy);
|
|
2073
|
+
|
|
2074
|
+
socket.end(
|
|
2075
|
+
`HTTP/1.1 ${code} ${http$3.STATUS_CODES[code]}\r\n` +
|
|
2076
|
+
Object.keys(headers)
|
|
2077
|
+
.map((h) => `${h}: ${headers[h]}`)
|
|
2078
|
+
.join('\r\n') +
|
|
2079
|
+
'\r\n\r\n' +
|
|
2080
|
+
message
|
|
2081
|
+
);
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
/**
|
|
2085
|
+
* Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
|
|
2086
|
+
* one listener for it, otherwise call `abortHandshake()`.
|
|
2087
|
+
*
|
|
2088
|
+
* @param {WebSocketServer} server The WebSocket server
|
|
2089
|
+
* @param {http.IncomingMessage} req The request object
|
|
2090
|
+
* @param {Duplex} socket The socket of the upgrade request
|
|
2091
|
+
* @param {Number} code The HTTP response status code
|
|
2092
|
+
* @param {String} message The HTTP response body
|
|
2093
|
+
* @private
|
|
2094
|
+
*/
|
|
2095
|
+
function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) {
|
|
2096
|
+
if (server.listenerCount('wsClientError')) {
|
|
2097
|
+
const err = new Error(message);
|
|
2098
|
+
Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
|
|
2099
|
+
|
|
2100
|
+
server.emit('wsClientError', err, socket, req);
|
|
2101
|
+
} else {
|
|
2102
|
+
abortHandshake(socket, code, message);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
var WebSocketServer$1 = /*@__PURE__*/index.getDefaultExportFromCjs(websocketServer);
|
|
2107
|
+
|
|
1507
2108
|
var application = {exports: {}};
|
|
1508
2109
|
|
|
1509
2110
|
var toStr$1 = Object.prototype.toString;
|
|
@@ -2122,8 +2723,8 @@ function requireNode$1 () {
|
|
|
2122
2723
|
if (hasRequiredNode$1) return node$1.exports;
|
|
2123
2724
|
hasRequiredNode$1 = 1;
|
|
2124
2725
|
(function (module, exports) {
|
|
2125
|
-
const tty = require$$0$
|
|
2126
|
-
const util = require$$1$
|
|
2726
|
+
const tty = require$$0$5;
|
|
2727
|
+
const util = require$$1$4;
|
|
2127
2728
|
|
|
2128
2729
|
/**
|
|
2129
2730
|
* This is the Node.js implementation of `debug()`.
|
|
@@ -2739,7 +3340,7 @@ var safeBuffer$2 = {exports: {}};
|
|
|
2739
3340
|
|
|
2740
3341
|
(function (module, exports) {
|
|
2741
3342
|
/* eslint-disable node/no-deprecated-api */
|
|
2742
|
-
var buffer = require$$0$
|
|
3343
|
+
var buffer = require$$0$6;
|
|
2743
3344
|
var Buffer = buffer.Buffer;
|
|
2744
3345
|
|
|
2745
3346
|
// alternative to using Object.keys for old browsers
|
|
@@ -2825,7 +3426,7 @@ contentDisposition$1.exports.parse = parse$k;
|
|
|
2825
3426
|
* @private
|
|
2826
3427
|
*/
|
|
2827
3428
|
|
|
2828
|
-
var basename$2 = require$$0$
|
|
3429
|
+
var basename$2 = require$$0$7.basename;
|
|
2829
3430
|
var Buffer$2 = safeBufferExports.Buffer;
|
|
2830
3431
|
|
|
2831
3432
|
/**
|
|
@@ -4200,7 +4801,7 @@ function status$1 (code) {
|
|
|
4200
4801
|
* @private
|
|
4201
4802
|
*/
|
|
4202
4803
|
|
|
4203
|
-
var EventEmitter$2 = require$$0$
|
|
4804
|
+
var EventEmitter$2 = require$$0$4.EventEmitter;
|
|
4204
4805
|
var ReadStream = require$$0$8.ReadStream;
|
|
4205
4806
|
var Stream$3 = require$$0$9;
|
|
4206
4807
|
var Zlib = zlib$1;
|
|
@@ -4631,10 +5232,10 @@ function encodeUrl (url) {
|
|
|
4631
5232
|
const statuses = statuses$2;
|
|
4632
5233
|
const destroy = destroy_1$2;
|
|
4633
5234
|
const assert = require$$0$b;
|
|
4634
|
-
const extname = require$$0$
|
|
5235
|
+
const extname = require$$0$7.extname;
|
|
4635
5236
|
const vary = varyExports;
|
|
4636
5237
|
const only = only$1;
|
|
4637
|
-
const util = require$$1$
|
|
5238
|
+
const util = require$$1$4;
|
|
4638
5239
|
const encodeUrl = encodeurl;
|
|
4639
5240
|
const Stream = require$$0$9;
|
|
4640
5241
|
const URL = require$$0$a.URL;
|
|
@@ -5420,7 +6021,7 @@ function requireEventListenerCount$1 () {
|
|
|
5420
6021
|
* @private
|
|
5421
6022
|
*/
|
|
5422
6023
|
|
|
5423
|
-
var EventEmitter = require$$0$
|
|
6024
|
+
var EventEmitter = require$$0$4.EventEmitter;
|
|
5424
6025
|
|
|
5425
6026
|
/**
|
|
5426
6027
|
* Module exports.
|
|
@@ -5502,7 +6103,7 @@ var compatExports$1 = compat$1.exports;
|
|
|
5502
6103
|
|
|
5503
6104
|
var callSiteToString$1 = compatExports$1.callSiteToString;
|
|
5504
6105
|
var eventListenerCount$1 = compatExports$1.eventListenerCount;
|
|
5505
|
-
var relative$2 = require$$0$
|
|
6106
|
+
var relative$2 = require$$0$7.relative;
|
|
5506
6107
|
|
|
5507
6108
|
/**
|
|
5508
6109
|
* Module exports.
|
|
@@ -6521,7 +7122,7 @@ function requireEventListenerCount () {
|
|
|
6521
7122
|
* @private
|
|
6522
7123
|
*/
|
|
6523
7124
|
|
|
6524
|
-
var EventEmitter = require$$0$
|
|
7125
|
+
var EventEmitter = require$$0$4.EventEmitter;
|
|
6525
7126
|
|
|
6526
7127
|
/**
|
|
6527
7128
|
* Module exports.
|
|
@@ -6603,7 +7204,7 @@ var compatExports = compat.exports;
|
|
|
6603
7204
|
|
|
6604
7205
|
var callSiteToString = compatExports.callSiteToString;
|
|
6605
7206
|
var eventListenerCount = compatExports.eventListenerCount;
|
|
6606
|
-
var relative$1 = require$$0$
|
|
7207
|
+
var relative$1 = require$$0$7.relative;
|
|
6607
7208
|
|
|
6608
7209
|
/**
|
|
6609
7210
|
* Module exports.
|
|
@@ -7729,7 +8330,7 @@ Delegator.prototype.fluent = function (name) {
|
|
|
7729
8330
|
* Module dependencies.
|
|
7730
8331
|
*/
|
|
7731
8332
|
|
|
7732
|
-
var relative = require$$0$
|
|
8333
|
+
var relative = require$$0$7.relative;
|
|
7733
8334
|
|
|
7734
8335
|
/**
|
|
7735
8336
|
* Module exports.
|
|
@@ -8264,7 +8865,7 @@ function DeprecationError (namespace, message, stack) {
|
|
|
8264
8865
|
// https://github.com/nodejs/node/issues/3043
|
|
8265
8866
|
// https://github.com/nodejs/node/pull/3073
|
|
8266
8867
|
|
|
8267
|
-
var crypto$3 = require$$1$
|
|
8868
|
+
var crypto$3 = require$$1$3;
|
|
8268
8869
|
|
|
8269
8870
|
function bufferEqual(a, b) {
|
|
8270
8871
|
if (a.length !== b.length) {
|
|
@@ -8302,7 +8903,7 @@ var lib$8 = timeSafeCompare;
|
|
|
8302
8903
|
*/
|
|
8303
8904
|
|
|
8304
8905
|
var compare$c = lib$8;
|
|
8305
|
-
var crypto$2 = require$$1$
|
|
8906
|
+
var crypto$2 = require$$1$3;
|
|
8306
8907
|
|
|
8307
8908
|
function Keygrip$1(keys, algorithm, encoding) {
|
|
8308
8909
|
if (!algorithm) algorithm = "sha1";
|
|
@@ -8640,7 +9241,7 @@ var cookies = Cookies;
|
|
|
8640
9241
|
* Module dependencies.
|
|
8641
9242
|
*/
|
|
8642
9243
|
|
|
8643
|
-
const util = require$$1$
|
|
9244
|
+
const util = require$$1$4;
|
|
8644
9245
|
const createError = httpErrorsExports$2;
|
|
8645
9246
|
const httpAssert$1 = httpAssert;
|
|
8646
9247
|
const delegate = delegates;
|
|
@@ -10585,7 +11186,7 @@ function parseTokenList (str) {
|
|
|
10585
11186
|
const typeis = typeIsExports;
|
|
10586
11187
|
const fresh = fresh_1;
|
|
10587
11188
|
const only = only$1;
|
|
10588
|
-
const util = require$$1$
|
|
11189
|
+
const util = require$$1$4;
|
|
10589
11190
|
|
|
10590
11191
|
const IP = Symbol('context#ip');
|
|
10591
11192
|
|
|
@@ -11652,8 +12253,8 @@ const compose$1 = koaCompose;
|
|
|
11652
12253
|
const context = contextExports;
|
|
11653
12254
|
const request = requestExports;
|
|
11654
12255
|
const statuses$1 = statuses$2;
|
|
11655
|
-
const Emitter = require$$0$
|
|
11656
|
-
const util$2 = require$$1$
|
|
12256
|
+
const Emitter = require$$0$4;
|
|
12257
|
+
const util$2 = require$$1$4;
|
|
11657
12258
|
const Stream$2 = require$$0$9;
|
|
11658
12259
|
const http$1 = require$$3$1;
|
|
11659
12260
|
const only = only$1;
|
|
@@ -13968,9 +14569,9 @@ for (const method of methods$1) {
|
|
|
13968
14569
|
|
|
13969
14570
|
Router.prototype.del = Router.prototype['delete'];
|
|
13970
14571
|
|
|
13971
|
-
var router$
|
|
14572
|
+
var router$i = Router;
|
|
13972
14573
|
|
|
13973
|
-
var Router$1 = /*@__PURE__*/index.getDefaultExportFromCjs(router$
|
|
14574
|
+
var Router$1 = /*@__PURE__*/index.getDefaultExportFromCjs(router$i);
|
|
13974
14575
|
|
|
13975
14576
|
const vary = varyExports;
|
|
13976
14577
|
|
|
@@ -14321,7 +14922,7 @@ var lib$7 = {exports: {}};
|
|
|
14321
14922
|
|
|
14322
14923
|
/* eslint-disable node/no-deprecated-api */
|
|
14323
14924
|
|
|
14324
|
-
var buffer$1 = require$$0$
|
|
14925
|
+
var buffer$1 = require$$0$6;
|
|
14325
14926
|
var Buffer$1 = buffer$1.Buffer;
|
|
14326
14927
|
|
|
14327
14928
|
var safer = {};
|
|
@@ -24903,7 +25504,7 @@ function requireStreams () {
|
|
|
24903
25504
|
if (hasRequiredStreams) return streams;
|
|
24904
25505
|
hasRequiredStreams = 1;
|
|
24905
25506
|
|
|
24906
|
-
var Buffer = require$$0$
|
|
25507
|
+
var Buffer = require$$0$6.Buffer,
|
|
24907
25508
|
Transform = require$$0$9.Transform;
|
|
24908
25509
|
|
|
24909
25510
|
|
|
@@ -25030,7 +25631,7 @@ var hasRequiredExtendNode;
|
|
|
25030
25631
|
function requireExtendNode () {
|
|
25031
25632
|
if (hasRequiredExtendNode) return extendNode;
|
|
25032
25633
|
hasRequiredExtendNode = 1;
|
|
25033
|
-
var Buffer = require$$0$
|
|
25634
|
+
var Buffer = require$$0$6.Buffer;
|
|
25034
25635
|
// Note: not polyfilled with safer-buffer on a purpose, as overrides Buffer
|
|
25035
25636
|
|
|
25036
25637
|
// == Extend Node primitives to use iconv-lite =================================
|
|
@@ -25063,7 +25664,7 @@ function requireExtendNode () {
|
|
|
25063
25664
|
};
|
|
25064
25665
|
|
|
25065
25666
|
// -- SlowBuffer -----------------------------------------------------------
|
|
25066
|
-
var SlowBuffer = require$$0$
|
|
25667
|
+
var SlowBuffer = require$$0$6.SlowBuffer;
|
|
25067
25668
|
|
|
25068
25669
|
original.SlowBufferToString = SlowBuffer.prototype.toString;
|
|
25069
25670
|
SlowBuffer.prototype.toString = function(encoding, start, end) {
|
|
@@ -25226,7 +25827,7 @@ function requireExtendNode () {
|
|
|
25226
25827
|
|
|
25227
25828
|
delete Buffer.isNativeEncoding;
|
|
25228
25829
|
|
|
25229
|
-
var SlowBuffer = require$$0$
|
|
25830
|
+
var SlowBuffer = require$$0$6.SlowBuffer;
|
|
25230
25831
|
|
|
25231
25832
|
SlowBuffer.prototype.toString = original.SlowBufferToString;
|
|
25232
25833
|
SlowBuffer.prototype.write = original.SlowBufferWrite;
|
|
@@ -26622,7 +27223,7 @@ var callBound$1 = function callBoundIntrinsic(name, allowMissing) {
|
|
|
26622
27223
|
return intrinsic;
|
|
26623
27224
|
};
|
|
26624
27225
|
|
|
26625
|
-
var util_inspect = require$$1$
|
|
27226
|
+
var util_inspect = require$$1$4.inspect;
|
|
26626
27227
|
|
|
26627
27228
|
var hasMap = typeof Map === 'function' && Map.prototype;
|
|
26628
27229
|
var mapSizeDescriptor = Object.getOwnPropertyDescriptor && hasMap ? Object.getOwnPropertyDescriptor(Map.prototype, 'size') : null;
|
|
@@ -30633,6 +31234,13 @@ function getRecorder(args) {
|
|
|
30633
31234
|
const data = recorderManager.config.getRaw(args.id);
|
|
30634
31235
|
return data;
|
|
30635
31236
|
}
|
|
31237
|
+
function getRecorderInfo(args) {
|
|
31238
|
+
const recorderManager = exports.container.resolve("recorderManager");
|
|
31239
|
+
const recorder = recorderManager.manager.recorders.find((item) => item.id === args.id);
|
|
31240
|
+
if (recorder == null)
|
|
31241
|
+
throw new Error("404");
|
|
31242
|
+
return recorderToClient(recorder);
|
|
31243
|
+
}
|
|
30636
31244
|
async function addRecorder(args) {
|
|
30637
31245
|
const recorderManager = exports.container.resolve("recorderManager");
|
|
30638
31246
|
const config = {
|
|
@@ -30686,6 +31294,27 @@ async function cutRecord(args) {
|
|
|
30686
31294
|
await recorderManager.manager.cutRecord(args.id);
|
|
30687
31295
|
return null;
|
|
30688
31296
|
}
|
|
31297
|
+
async function getRecentRecordFolder(args) {
|
|
31298
|
+
const recorderManager = exports.container.resolve("recorderManager");
|
|
31299
|
+
const recorder = recorderManager.manager.recorders.find((item) => item.id === args.id);
|
|
31300
|
+
if (!recorder) {
|
|
31301
|
+
throw new Error("录制器不存在");
|
|
31302
|
+
}
|
|
31303
|
+
const recentCandidates = index.recordHistory.queryRecentClipsByRoomAndPlatform({
|
|
31304
|
+
room_id: recorder.channelId,
|
|
31305
|
+
platform: recorder.providerId,
|
|
31306
|
+
candidateLimit: 15,
|
|
31307
|
+
});
|
|
31308
|
+
for (const clip of recentCandidates) {
|
|
31309
|
+
const videoFile = clip.video_file;
|
|
31310
|
+
if (!videoFile)
|
|
31311
|
+
continue;
|
|
31312
|
+
return {
|
|
31313
|
+
folderPath: path$7.dirname(videoFile),
|
|
31314
|
+
};
|
|
31315
|
+
}
|
|
31316
|
+
throw new Error("未找到最近录制文件");
|
|
31317
|
+
}
|
|
30689
31318
|
async function getBiliStream(id) {
|
|
30690
31319
|
const recorderManager = exports.container.resolve("recorderManager");
|
|
30691
31320
|
const recorder = recorderManager.manager.recorders.find((item) => item.id === id);
|
|
@@ -30729,7 +31358,7 @@ async function getBiliStream(id) {
|
|
|
30729
31358
|
}
|
|
30730
31359
|
function recorderToClient(recorder) {
|
|
30731
31360
|
return {
|
|
30732
|
-
...index.omit(recorder, "all", "getChannelURL", "checkLiveStatusAndRecord", "recordHandle", "toJSON", "getLiveInfo", "auth"),
|
|
31361
|
+
...index.omit(recorder, "all", "getChannelURL", "checkLiveStatusAndRecord", "appendTimeline", "recordHandle", "toJSON", "getLiveInfo", "auth"),
|
|
30733
31362
|
channelURL: recorder.getChannelURL(),
|
|
30734
31363
|
recordHandle: recorder.recordHandle && index.omit(recorder.recordHandle, "stop"),
|
|
30735
31364
|
liveInfo: recorder.liveInfo,
|
|
@@ -30867,12 +31496,14 @@ var recorderService = {
|
|
|
30867
31496
|
getRecorders,
|
|
30868
31497
|
getRecorderNum,
|
|
30869
31498
|
getRecorder,
|
|
31499
|
+
getRecorderInfo,
|
|
30870
31500
|
addRecorder,
|
|
30871
31501
|
updateRecorder,
|
|
30872
31502
|
removeRecorder,
|
|
30873
31503
|
startRecord,
|
|
30874
31504
|
stopRecord,
|
|
30875
31505
|
cutRecord,
|
|
31506
|
+
getRecentRecordFolder,
|
|
30876
31507
|
getLiveInfo,
|
|
30877
31508
|
batchStartRecord,
|
|
30878
31509
|
batchStopRecord,
|
|
@@ -30882,11 +31513,11 @@ var recorderService = {
|
|
|
30882
31513
|
resolve,
|
|
30883
31514
|
};
|
|
30884
31515
|
|
|
30885
|
-
const router$
|
|
30886
|
-
router$
|
|
31516
|
+
const router$h = new Router$1();
|
|
31517
|
+
router$h.get("/webhook", async (ctx) => {
|
|
30887
31518
|
ctx.body = "webhook 服务器已启动";
|
|
30888
31519
|
});
|
|
30889
|
-
router$
|
|
31520
|
+
router$h.post("/webhook/bililiverecorder", async (ctx) => {
|
|
30890
31521
|
const config = exports.appConfig.getAll();
|
|
30891
31522
|
index.logObj.info("录播姬:", ctx.request.body);
|
|
30892
31523
|
const event = ctx.request.body;
|
|
@@ -30915,7 +31546,7 @@ router$g.post("/webhook/bililiverecorder", async (ctx) => {
|
|
|
30915
31546
|
}
|
|
30916
31547
|
ctx.body = "ok";
|
|
30917
31548
|
});
|
|
30918
|
-
router$
|
|
31549
|
+
router$h.post("/webhook/blrec", async (ctx) => {
|
|
30919
31550
|
const webhook = exports.appConfig.get("webhook");
|
|
30920
31551
|
index.logObj.info("blrec webhook:", ctx.request.body);
|
|
30921
31552
|
const event = ctx.request.body;
|
|
@@ -30950,7 +31581,7 @@ router$g.post("/webhook/blrec", async (ctx) => {
|
|
|
30950
31581
|
* OneLiveRec webhook事件处理
|
|
30951
31582
|
* 由于只有在结束后才能从文件的备注中获取到,只处理结束事件获取信息后模拟开始和结束事件
|
|
30952
31583
|
*/
|
|
30953
|
-
router$
|
|
31584
|
+
router$h.post("/webhook/oneliverec", async (ctx) => {
|
|
30954
31585
|
const webhook = exports.appConfig.get("webhook");
|
|
30955
31586
|
index.logObj.info("oneliverec webhook:", ctx.request.body);
|
|
30956
31587
|
const event = ctx.request.body;
|
|
@@ -30986,7 +31617,7 @@ router$g.post("/webhook/oneliverec", async (ctx) => {
|
|
|
30986
31617
|
}
|
|
30987
31618
|
ctx.body = "ok";
|
|
30988
31619
|
});
|
|
30989
|
-
router$
|
|
31620
|
+
router$h.post("/webhook/ddtv", async (ctx) => {
|
|
30990
31621
|
const webhook = exports.appConfig.get("webhook");
|
|
30991
31622
|
const event = ctx.request.body;
|
|
30992
31623
|
if (webhook?.open && (event.cmd === "RecordingEnd" || event.cmd === "StartRecording")) {
|
|
@@ -31044,7 +31675,7 @@ const getDDTVTrueFile = (event) => {
|
|
|
31044
31675
|
danmuFile: danmuFileTruePath,
|
|
31045
31676
|
};
|
|
31046
31677
|
};
|
|
31047
|
-
router$
|
|
31678
|
+
router$h.post("/webhook/custom", async (ctx) => {
|
|
31048
31679
|
const webhook = exports.appConfig.get("webhook");
|
|
31049
31680
|
index.logObj.info("custom: webhook", ctx.request.body);
|
|
31050
31681
|
const event = ctx.request.body;
|
|
@@ -31093,7 +31724,7 @@ async function checkFileInterval() {
|
|
|
31093
31724
|
}
|
|
31094
31725
|
}, 1000 * 60);
|
|
31095
31726
|
}
|
|
31096
|
-
router$
|
|
31727
|
+
router$h.get("/bili/stream", async (ctx) => {
|
|
31097
31728
|
const { id } = ctx.query;
|
|
31098
31729
|
try {
|
|
31099
31730
|
const m3u8Content = await recorderService.getBiliStream(id);
|
|
@@ -31201,7 +31832,7 @@ function requireSafeBuffer$1 () {
|
|
|
31201
31832
|
if (hasRequiredSafeBuffer$1) return safeBuffer$1.exports;
|
|
31202
31833
|
hasRequiredSafeBuffer$1 = 1;
|
|
31203
31834
|
(function (module, exports) {
|
|
31204
|
-
var buffer = require$$0$
|
|
31835
|
+
var buffer = require$$0$6;
|
|
31205
31836
|
var Buffer = buffer.Buffer;
|
|
31206
31837
|
|
|
31207
31838
|
// alternative to using Object.keys for old browsers
|
|
@@ -31375,7 +32006,7 @@ function requireUtil () {
|
|
|
31375
32006
|
}
|
|
31376
32007
|
util$1.isPrimitive = isPrimitive;
|
|
31377
32008
|
|
|
31378
|
-
util$1.isBuffer = require$$0$
|
|
32009
|
+
util$1.isBuffer = require$$0$6.Buffer.isBuffer;
|
|
31379
32010
|
|
|
31380
32011
|
function objectToString(o) {
|
|
31381
32012
|
return Object.prototype.toString.call(o);
|
|
@@ -31395,7 +32026,7 @@ function requireBufferList () {
|
|
|
31395
32026
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
31396
32027
|
|
|
31397
32028
|
var Buffer = requireSafeBuffer$1().Buffer;
|
|
31398
|
-
var util = require$$1$
|
|
32029
|
+
var util = require$$1$4;
|
|
31399
32030
|
|
|
31400
32031
|
function copyBuffer(src, target, offset) {
|
|
31401
32032
|
src.copy(target, offset);
|
|
@@ -31574,7 +32205,7 @@ function requireNode () {
|
|
|
31574
32205
|
* For Node.js, simply re-export the core `util.deprecate` function.
|
|
31575
32206
|
*/
|
|
31576
32207
|
|
|
31577
|
-
node = require$$1$
|
|
32208
|
+
node = require$$1$4.deprecate;
|
|
31578
32209
|
return node;
|
|
31579
32210
|
}
|
|
31580
32211
|
|
|
@@ -32363,7 +32994,7 @@ function requireSafeBuffer () {
|
|
|
32363
32994
|
if (hasRequiredSafeBuffer) return safeBuffer.exports;
|
|
32364
32995
|
hasRequiredSafeBuffer = 1;
|
|
32365
32996
|
(function (module, exports) {
|
|
32366
|
-
var buffer = require$$0$
|
|
32997
|
+
var buffer = require$$0$6;
|
|
32367
32998
|
var Buffer = buffer.Buffer;
|
|
32368
32999
|
|
|
32369
33000
|
// alternative to using Object.keys for old browsers
|
|
@@ -32734,7 +33365,7 @@ function require_stream_readable$1 () {
|
|
|
32734
33365
|
Readable.ReadableState = ReadableState;
|
|
32735
33366
|
|
|
32736
33367
|
/*<replacement>*/
|
|
32737
|
-
require$$0$
|
|
33368
|
+
require$$0$4.EventEmitter;
|
|
32738
33369
|
|
|
32739
33370
|
var EElistenerCount = function (emitter, type) {
|
|
32740
33371
|
return emitter.listeners(type).length;
|
|
@@ -32764,7 +33395,7 @@ function require_stream_readable$1 () {
|
|
|
32764
33395
|
/*</replacement>*/
|
|
32765
33396
|
|
|
32766
33397
|
/*<replacement>*/
|
|
32767
|
-
var debugUtil = require$$1$
|
|
33398
|
+
var debugUtil = require$$1$4;
|
|
32768
33399
|
var debug = void 0;
|
|
32769
33400
|
if (debugUtil && debugUtil.debuglog) {
|
|
32770
33401
|
debug = debugUtil.debuglog('stream');
|
|
@@ -47493,7 +48124,7 @@ function appendField$1 (store, key, value) {
|
|
|
47493
48124
|
|
|
47494
48125
|
var appendField_1 = appendField$1;
|
|
47495
48126
|
|
|
47496
|
-
var EventEmitter$1 = require$$0$
|
|
48127
|
+
var EventEmitter$1 = require$$0$4.EventEmitter;
|
|
47497
48128
|
|
|
47498
48129
|
function Counter$1 () {
|
|
47499
48130
|
EventEmitter$1.call(this);
|
|
@@ -47522,7 +48153,7 @@ Counter$1.prototype.onceZero = function onceZero (fn) {
|
|
|
47522
48153
|
|
|
47523
48154
|
var counter = Counter$1;
|
|
47524
48155
|
|
|
47525
|
-
var util = require$$1$
|
|
48156
|
+
var util = require$$1$4;
|
|
47526
48157
|
|
|
47527
48158
|
var errorMessages = {
|
|
47528
48159
|
LIMIT_PART_COUNT: 'Too many parts',
|
|
@@ -47907,7 +48538,7 @@ function makeMiddleware$1 (setup) {
|
|
|
47907
48538
|
|
|
47908
48539
|
var makeMiddleware_1 = makeMiddleware$1;
|
|
47909
48540
|
|
|
47910
|
-
var path$6 = require$$0$
|
|
48541
|
+
var path$6 = require$$0$7;
|
|
47911
48542
|
var fs$5 = require$$0$8;
|
|
47912
48543
|
var _0777 = parseInt('0777', 8);
|
|
47913
48544
|
|
|
@@ -48012,8 +48643,8 @@ mkdirP.sync = function sync (p, opts, made) {
|
|
|
48012
48643
|
|
|
48013
48644
|
var fs$4 = require$$0$8;
|
|
48014
48645
|
var os = require$$1$6;
|
|
48015
|
-
var path$5 = require$$0$
|
|
48016
|
-
var crypto$1 = require$$1$
|
|
48646
|
+
var path$5 = require$$0$7;
|
|
48647
|
+
var crypto$1 = require$$1$3;
|
|
48017
48648
|
var mkdirp = mkdirp$1;
|
|
48018
48649
|
|
|
48019
48650
|
function getFilename (req, file, cb) {
|
|
@@ -49108,21 +49739,21 @@ function makePromise(multer, name) {
|
|
|
49108
49739
|
multer.diskStorage = originalMulter.diskStorage;
|
|
49109
49740
|
multer.memoryStorage = originalMulter.memoryStorage;
|
|
49110
49741
|
|
|
49111
|
-
const router$
|
|
49742
|
+
const router$g = new Router$1({
|
|
49112
49743
|
prefix: "/config",
|
|
49113
49744
|
});
|
|
49114
49745
|
const upload$1 = multer({ dest: os$1.tmpdir() });
|
|
49115
|
-
router$
|
|
49746
|
+
router$g.get("/", async (ctx) => {
|
|
49116
49747
|
const config = exports.appConfig.getAll();
|
|
49117
49748
|
ctx.body = config;
|
|
49118
49749
|
});
|
|
49119
|
-
router$
|
|
49750
|
+
router$g.post("/", async (ctx) => {
|
|
49120
49751
|
const data = ctx.request.body;
|
|
49121
49752
|
// @ts-ignore
|
|
49122
49753
|
exports.appConfig.setAll(data);
|
|
49123
49754
|
ctx.body = "success";
|
|
49124
49755
|
});
|
|
49125
|
-
router$
|
|
49756
|
+
router$g.post("/set", async (ctx) => {
|
|
49126
49757
|
const data = ctx.request.body;
|
|
49127
49758
|
if (!data.key || !data.value) {
|
|
49128
49759
|
ctx.body = "key and value is required";
|
|
@@ -49132,7 +49763,7 @@ router$f.post("/set", async (ctx) => {
|
|
|
49132
49763
|
exports.appConfig.set(data.key, data.value);
|
|
49133
49764
|
ctx.body = "success";
|
|
49134
49765
|
});
|
|
49135
|
-
router$
|
|
49766
|
+
router$g.post("/verifyBiliKey", async (ctx) => {
|
|
49136
49767
|
try {
|
|
49137
49768
|
const serverKey = process.env.BILILIVE_TOOLS_BILIKEY;
|
|
49138
49769
|
const configured = typeof serverKey === "string" && serverKey.trim().length > 0;
|
|
@@ -49176,7 +49807,7 @@ router$f.post("/verifyBiliKey", async (ctx) => {
|
|
|
49176
49807
|
ctx.body = response;
|
|
49177
49808
|
}
|
|
49178
49809
|
});
|
|
49179
|
-
router$
|
|
49810
|
+
router$g.post("/resetBin", async (ctx) => {
|
|
49180
49811
|
const data = ctx.request.body;
|
|
49181
49812
|
const type = data.type;
|
|
49182
49813
|
if (!type) {
|
|
@@ -49233,7 +49864,7 @@ async function exportConfig(opts) {
|
|
|
49233
49864
|
const content = zip.generateNodeStream({ type: "nodebuffer" });
|
|
49234
49865
|
return content;
|
|
49235
49866
|
}
|
|
49236
|
-
router$
|
|
49867
|
+
router$g.get("/export", async (ctx) => {
|
|
49237
49868
|
try {
|
|
49238
49869
|
const globalConfig = exports.container.resolve("globalConfig");
|
|
49239
49870
|
const { configPath, videoPresetPath, danmuPresetPath, ffmpegPresetPath, userDataPath } = globalConfig;
|
|
@@ -49266,7 +49897,7 @@ router$f.get("/export", async (ctx) => {
|
|
|
49266
49897
|
ctx.body = "export error";
|
|
49267
49898
|
}
|
|
49268
49899
|
});
|
|
49269
|
-
router$
|
|
49900
|
+
router$g.post("/import", upload$1.single("file"), async (ctx) => {
|
|
49270
49901
|
const file = ctx.request?.file?.path;
|
|
49271
49902
|
if (!file) {
|
|
49272
49903
|
ctx.status = 400;
|
|
@@ -49325,7 +49956,7 @@ router$f.post("/import", upload$1.single("file"), async (ctx) => {
|
|
|
49325
49956
|
}));
|
|
49326
49957
|
ctx.body = "success";
|
|
49327
49958
|
});
|
|
49328
|
-
router$
|
|
49959
|
+
router$g.post("/notifyTest", async (ctx) => {
|
|
49329
49960
|
const { title, desp, options, notifyType } = ctx.request.body;
|
|
49330
49961
|
await index._send(title, desp, options, notifyType);
|
|
49331
49962
|
ctx.body = "success";
|
|
@@ -50400,7 +51031,7 @@ class Ollama extends Ollama$1 {
|
|
|
50400
51031
|
}
|
|
50401
51032
|
try {
|
|
50402
51033
|
if (require$$0$8.existsSync(image)) {
|
|
50403
|
-
const fileBuffer = await require$$0$8.promises.readFile(require$$0$
|
|
51034
|
+
const fileBuffer = await require$$0$8.promises.readFile(require$$0$7.resolve(image));
|
|
50404
51035
|
return Buffer.from(fileBuffer).toString("base64");
|
|
50405
51036
|
}
|
|
50406
51037
|
} catch {
|
|
@@ -50439,9 +51070,9 @@ class Ollama extends Ollama$1 {
|
|
|
50439
51070
|
*/
|
|
50440
51071
|
resolvePath(inputPath, mfDir) {
|
|
50441
51072
|
if (inputPath.startsWith("~")) {
|
|
50442
|
-
return require$$0$
|
|
51073
|
+
return require$$0$7.join(require$$1$6.homedir(), inputPath.slice(1));
|
|
50443
51074
|
}
|
|
50444
|
-
return require$$0$
|
|
51075
|
+
return require$$0$7.resolve(mfDir, inputPath);
|
|
50445
51076
|
}
|
|
50446
51077
|
/**
|
|
50447
51078
|
* checks if a file exists
|
|
@@ -50463,7 +51094,7 @@ class Ollama extends Ollama$1 {
|
|
|
50463
51094
|
}
|
|
50464
51095
|
const fileStream = require$$0$8.createReadStream(path);
|
|
50465
51096
|
const sha256sum = await new Promise((resolve2, reject) => {
|
|
50466
|
-
const hash = require$$1$
|
|
51097
|
+
const hash = require$$1$3.createHash("sha256");
|
|
50467
51098
|
fileStream.on("data", (data) => hash.update(data));
|
|
50468
51099
|
fileStream.on("end", () => resolve2(hash.digest("hex")));
|
|
50469
51100
|
fileStream.on("error", reject);
|
|
@@ -50503,7 +51134,7 @@ class Ollama extends Ollama$1 {
|
|
|
50503
51134
|
modelfileContent = await require$$0$8.promises.readFile(request.path, { encoding: "utf8" });
|
|
50504
51135
|
modelfileContent = await this.parseModelfile(
|
|
50505
51136
|
modelfileContent,
|
|
50506
|
-
require$$0$
|
|
51137
|
+
require$$0$7.dirname(request.path)
|
|
50507
51138
|
);
|
|
50508
51139
|
} else if (request.modelfile) {
|
|
50509
51140
|
modelfileContent = await this.parseModelfile(request.modelfile);
|
|
@@ -50651,9 +51282,9 @@ function requireBuffer_list () {
|
|
|
50651
51282
|
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
50652
51283
|
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
50653
51284
|
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
50654
|
-
var _require = require$$0$
|
|
51285
|
+
var _require = require$$0$6,
|
|
50655
51286
|
Buffer = _require.Buffer;
|
|
50656
|
-
var _require2 = require$$1$
|
|
51287
|
+
var _require2 = require$$1$4,
|
|
50657
51288
|
inspect = _require2.inspect;
|
|
50658
51289
|
var custom = inspect && inspect.custom || 'inspect';
|
|
50659
51290
|
function copyBuffer(src, target, offset) {
|
|
@@ -51123,7 +51754,7 @@ function require_stream_writable () {
|
|
|
51123
51754
|
var Stream = requireStream();
|
|
51124
51755
|
/*</replacement>*/
|
|
51125
51756
|
|
|
51126
|
-
var Buffer = require$$0$
|
|
51757
|
+
var Buffer = require$$0$6.Buffer;
|
|
51127
51758
|
var OurUint8Array = (typeof index.commonjsGlobal !== 'undefined' ? index.commonjsGlobal : typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : {}).Uint8Array || function () {};
|
|
51128
51759
|
function _uint8ArrayToBuffer(chunk) {
|
|
51129
51760
|
return Buffer.from(chunk);
|
|
@@ -52448,7 +53079,7 @@ function require_stream_readable () {
|
|
|
52448
53079
|
Readable.ReadableState = ReadableState;
|
|
52449
53080
|
|
|
52450
53081
|
/*<replacement>*/
|
|
52451
|
-
require$$0$
|
|
53082
|
+
require$$0$4.EventEmitter;
|
|
52452
53083
|
var EElistenerCount = function EElistenerCount(emitter, type) {
|
|
52453
53084
|
return emitter.listeners(type).length;
|
|
52454
53085
|
};
|
|
@@ -52458,7 +53089,7 @@ function require_stream_readable () {
|
|
|
52458
53089
|
var Stream = requireStream();
|
|
52459
53090
|
/*</replacement>*/
|
|
52460
53091
|
|
|
52461
|
-
var Buffer = require$$0$
|
|
53092
|
+
var Buffer = require$$0$6.Buffer;
|
|
52462
53093
|
var OurUint8Array = (typeof index.commonjsGlobal !== 'undefined' ? index.commonjsGlobal : typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : {}).Uint8Array || function () {};
|
|
52463
53094
|
function _uint8ArrayToBuffer(chunk) {
|
|
52464
53095
|
return Buffer.from(chunk);
|
|
@@ -52468,7 +53099,7 @@ function require_stream_readable () {
|
|
|
52468
53099
|
}
|
|
52469
53100
|
|
|
52470
53101
|
/*<replacement>*/
|
|
52471
|
-
var debugUtil = require$$1$
|
|
53102
|
+
var debugUtil = require$$1$4;
|
|
52472
53103
|
var debug;
|
|
52473
53104
|
if (debugUtil && debugUtil.debuglog) {
|
|
52474
53105
|
debug = debugUtil.debuglog('stream');
|
|
@@ -54117,15 +54748,15 @@ async function handleSrt(input, output) {
|
|
|
54117
54748
|
return nodes;
|
|
54118
54749
|
}
|
|
54119
54750
|
|
|
54120
|
-
const router$
|
|
54751
|
+
const router$f = new Router$1({
|
|
54121
54752
|
prefix: "/llm",
|
|
54122
54753
|
});
|
|
54123
|
-
router$
|
|
54754
|
+
router$f.get("/ollama/modelList", async (ctx) => {
|
|
54124
54755
|
const data = ctx.request.query;
|
|
54125
54756
|
const models = (await ollama.getModelList(data.baseUrl)).models.map((item) => item.name);
|
|
54126
54757
|
ctx.body = models;
|
|
54127
54758
|
});
|
|
54128
|
-
router$
|
|
54759
|
+
router$f.post("/translate", async (ctx) => {
|
|
54129
54760
|
const data = ctx.request.body;
|
|
54130
54761
|
console.log(data);
|
|
54131
54762
|
const content = await addTranslateTask(data.input, data.output);
|
|
@@ -56436,11 +57067,10 @@ var semver = {
|
|
|
56436
57067
|
|
|
56437
57068
|
var semver$1 = /*@__PURE__*/index.getDefaultExportFromCjs(semver);
|
|
56438
57069
|
|
|
56439
|
-
const router$
|
|
57070
|
+
const router$e = new Router$1({
|
|
56440
57071
|
prefix: "/common",
|
|
56441
57072
|
});
|
|
56442
|
-
|
|
56443
|
-
router$d.get("/version", (ctx) => {
|
|
57073
|
+
router$e.get("/version", (ctx) => {
|
|
56444
57074
|
ctx.body = exports.config.version;
|
|
56445
57075
|
});
|
|
56446
57076
|
function getDriveLetters() {
|
|
@@ -56462,7 +57092,7 @@ function getDriveLetters() {
|
|
|
56462
57092
|
function isDriveLetter(letter) {
|
|
56463
57093
|
return /^[a-zA-Z]:\\$/.test(letter);
|
|
56464
57094
|
}
|
|
56465
|
-
router$
|
|
57095
|
+
router$e.get("/files", async (ctx) => {
|
|
56466
57096
|
const params = ctx.request.query;
|
|
56467
57097
|
let root = params.path;
|
|
56468
57098
|
const filterExts = (params.exts || "")
|
|
@@ -56518,56 +57148,26 @@ router$d.get("/files", async (ctx) => {
|
|
|
56518
57148
|
return;
|
|
56519
57149
|
}
|
|
56520
57150
|
});
|
|
56521
|
-
router$
|
|
56522
|
-
const { dir, name } = ctx.request.body;
|
|
56523
|
-
if (!index.fs.existsSync(dir)) {
|
|
56524
|
-
ctx.status = 400;
|
|
56525
|
-
ctx.body = "文件夹不存在";
|
|
56526
|
-
return;
|
|
56527
|
-
}
|
|
56528
|
-
const filePath = path$7.join(dir, name);
|
|
56529
|
-
ctx.body = filePath;
|
|
56530
|
-
});
|
|
56531
|
-
router$d.post("/danma/timestamp", async (ctx) => {
|
|
57151
|
+
router$e.post("/danma/timestamp", async (ctx) => {
|
|
56532
57152
|
const { filepath } = ctx.request.body;
|
|
56533
57153
|
ctx.body = await index.readXmlTimestamp(filepath);
|
|
56534
57154
|
});
|
|
56535
|
-
router$
|
|
57155
|
+
router$e.post("/parseVideoMetadata", async (ctx) => {
|
|
56536
57156
|
const files = ctx.request.body;
|
|
56537
57157
|
ctx.body = await index.parseMeta(files);
|
|
56538
57158
|
});
|
|
56539
57159
|
/**
|
|
56540
57160
|
* @api {get} /common/fonts 获取系统字体列表
|
|
56541
57161
|
*/
|
|
56542
|
-
router$
|
|
57162
|
+
router$e.get("/fonts", async (ctx) => {
|
|
56543
57163
|
const { getFontsList } = await Promise.resolve().then(function () { return require('./fonts-DxTEygXH.cjs'); });
|
|
56544
57164
|
ctx.body = await getFontsList();
|
|
56545
57165
|
});
|
|
56546
|
-
router$
|
|
56547
|
-
const file = ctx.request?.file?.path;
|
|
56548
|
-
if (!file) {
|
|
56549
|
-
ctx.status = 400;
|
|
56550
|
-
ctx.body = "No file selected";
|
|
56551
|
-
return;
|
|
56552
|
-
}
|
|
56553
|
-
const originalname = ctx.request?.file?.originalname;
|
|
56554
|
-
const ext = path$7.extname(originalname);
|
|
56555
|
-
const coverPath = path$7.join(exports.config.userDataPath, "cover");
|
|
56556
|
-
const outputName = `${index.uuid()}${ext}`;
|
|
56557
|
-
// 将图片复制到指定目录
|
|
56558
|
-
await index.fs.ensureDir(coverPath);
|
|
56559
|
-
await index.fs.copyFile(file, path$7.join(coverPath, outputName));
|
|
56560
|
-
await index.fs.remove(file).catch(() => { });
|
|
56561
|
-
ctx.body = {
|
|
56562
|
-
name: outputName,
|
|
56563
|
-
path: `/assets/cover/${outputName}`,
|
|
56564
|
-
};
|
|
56565
|
-
});
|
|
56566
|
-
router$d.get("/appStartTime", async (ctx) => {
|
|
57166
|
+
router$e.get("/appStartTime", async (ctx) => {
|
|
56567
57167
|
const data = index.statisticsService.query("start_time");
|
|
56568
57168
|
ctx.body = data?.value;
|
|
56569
57169
|
});
|
|
56570
|
-
router$
|
|
57170
|
+
router$e.get("/statistics", async (ctx) => {
|
|
56571
57171
|
const startTime = index.statisticsService.query("start_time");
|
|
56572
57172
|
const videoTotalDuaration = index.recordHistoryService.getTotalDuration();
|
|
56573
57173
|
const recordingNum = recorderService.getRecorderNum(true);
|
|
@@ -56579,16 +57179,16 @@ router$d.get("/statistics", async (ctx) => {
|
|
|
56579
57179
|
recorderNum,
|
|
56580
57180
|
};
|
|
56581
57181
|
});
|
|
56582
|
-
router$
|
|
57182
|
+
router$e.get("/exportLogs", async (ctx) => {
|
|
56583
57183
|
const logFilePath = exports.config.logPath;
|
|
56584
57184
|
ctx.body = index.fs.createReadStream(logFilePath);
|
|
56585
57185
|
});
|
|
56586
|
-
router$
|
|
57186
|
+
router$e.get("/getLogContent", async (ctx) => {
|
|
56587
57187
|
const logFilePath = exports.config.logPath;
|
|
56588
57188
|
const content = await index.fs.readFile(logFilePath, "utf-8");
|
|
56589
57189
|
ctx.body = content;
|
|
56590
57190
|
});
|
|
56591
|
-
router$
|
|
57191
|
+
router$e.post("/readDanma", async (ctx) => {
|
|
56592
57192
|
const { filepath } = ctx.request.body;
|
|
56593
57193
|
// 只允许读取ass或xml文件
|
|
56594
57194
|
if (!filepath.endsWith(".ass") && !filepath.endsWith(".xml") && !filepath.endsWith(".srt")) {
|
|
@@ -56604,7 +57204,7 @@ router$d.post("/readDanma", async (ctx) => {
|
|
|
56604
57204
|
const content = await index.fs.readFile(filepath, "utf-8");
|
|
56605
57205
|
ctx.body = content;
|
|
56606
57206
|
});
|
|
56607
|
-
router$
|
|
57207
|
+
router$e.post("/readLLC", async (ctx) => {
|
|
56608
57208
|
const { filepath } = ctx.request.body;
|
|
56609
57209
|
if (!(await index.fs.pathExists(filepath))) {
|
|
56610
57210
|
ctx.status = 400;
|
|
@@ -56619,7 +57219,7 @@ router$d.post("/readLLC", async (ctx) => {
|
|
|
56619
57219
|
}
|
|
56620
57220
|
ctx.body = content;
|
|
56621
57221
|
});
|
|
56622
|
-
router$
|
|
57222
|
+
router$e.post("/writeLLC", async (ctx) => {
|
|
56623
57223
|
const { filepath, content } = ctx.request.body;
|
|
56624
57224
|
if (!content.includes("cutSegments")) {
|
|
56625
57225
|
ctx.status = 400;
|
|
@@ -56629,18 +57229,13 @@ router$d.post("/writeLLC", async (ctx) => {
|
|
|
56629
57229
|
await index.fs.writeFile(filepath, content, "utf-8");
|
|
56630
57230
|
ctx.body = "success";
|
|
56631
57231
|
});
|
|
56632
|
-
router$
|
|
56633
|
-
const { filepath } = ctx.request.body;
|
|
56634
|
-
const exists = await index.fs.pathExists(filepath);
|
|
56635
|
-
ctx.body = exists;
|
|
56636
|
-
});
|
|
56637
|
-
router$d.post("/genTimeData", async (ctx) => {
|
|
57232
|
+
router$e.post("/genTimeData", async (ctx) => {
|
|
56638
57233
|
const { filepath } = ctx.request.body;
|
|
56639
57234
|
const data = await index.genTimeData(filepath);
|
|
56640
57235
|
ctx.body = data;
|
|
56641
57236
|
});
|
|
56642
57237
|
// 申请视频ID接口
|
|
56643
|
-
router$
|
|
57238
|
+
router$e.post("/applyVideoId", async (ctx) => {
|
|
56644
57239
|
const { videoPath } = ctx.request.body;
|
|
56645
57240
|
if (!(await index.fs.pathExists(videoPath))) {
|
|
56646
57241
|
ctx.status = 404;
|
|
@@ -56682,6 +57277,7 @@ router$d.post("/apply-video-id", async (ctx) => {
|
|
|
56682
57277
|
const expireAt = Date.now() + 24 * 60 * 60 * 1000;
|
|
56683
57278
|
// 存储ID和视频路径的映射关系
|
|
56684
57279
|
fileCache.set(videoId, { path: videoPath, expireAt });
|
|
57280
|
+
// 这玩意不能轻易改,空就是默认值
|
|
56685
57281
|
let type = "";
|
|
56686
57282
|
switch (extname) {
|
|
56687
57283
|
case ".flv":
|
|
@@ -56697,7 +57293,7 @@ router$d.post("/apply-video-id", async (ctx) => {
|
|
|
56697
57293
|
type,
|
|
56698
57294
|
};
|
|
56699
57295
|
});
|
|
56700
|
-
router$
|
|
57296
|
+
router$e.get("/video/:videoId", async (ctx) => {
|
|
56701
57297
|
const videoId = ctx.params.videoId;
|
|
56702
57298
|
// 从映射表中获取视频路径
|
|
56703
57299
|
const videoInfo = fileCache.get(videoId);
|
|
@@ -56758,20 +57354,26 @@ router$d.get("/video/:videoId", async (ctx) => {
|
|
|
56758
57354
|
ctx.body = file;
|
|
56759
57355
|
}
|
|
56760
57356
|
else {
|
|
57357
|
+
const MAX_CHUNK_SIZE = 1024 * 1024 * 1; // 1MB
|
|
56761
57358
|
const head = {
|
|
56762
|
-
"Content-Length":
|
|
57359
|
+
"Content-Length": MAX_CHUNK_SIZE,
|
|
56763
57360
|
"Content-Type": contentType,
|
|
57361
|
+
"Content-Range": `bytes 0-${Math.min(MAX_CHUNK_SIZE - 1, fileSize - 1)}/${fileSize}`,
|
|
57362
|
+
"Accept-Ranges": "bytes",
|
|
56764
57363
|
};
|
|
56765
|
-
ctx.res.writeHead(
|
|
56766
|
-
|
|
57364
|
+
ctx.res.writeHead(206, head);
|
|
57365
|
+
const start = 0;
|
|
57366
|
+
const end = Math.min(MAX_CHUNK_SIZE - 1, fileSize - 1);
|
|
57367
|
+
const file = index.fs.createReadStream(videoPath, { start, end });
|
|
57368
|
+
ctx.body = file;
|
|
56767
57369
|
}
|
|
56768
57370
|
});
|
|
56769
|
-
router$
|
|
57371
|
+
router$e.post("/parseDanmu", async (ctx) => {
|
|
56770
57372
|
const { filepath } = ctx.request.body;
|
|
56771
57373
|
const data = await index.parseDanmu(filepath);
|
|
56772
57374
|
ctx.body = data;
|
|
56773
57375
|
});
|
|
56774
|
-
router$
|
|
57376
|
+
router$e.post("/testWebhook", async (ctx) => {
|
|
56775
57377
|
const list = [];
|
|
56776
57378
|
// 检查所有live数据,如果存在同一个live中,前一个part还在录制中,但是后面的part已经是其他状态,则返回相关id以及文件
|
|
56777
57379
|
const liveList = exports.handler.liveData;
|
|
@@ -56793,7 +57395,7 @@ router$d.post("/testWebhook", async (ctx) => {
|
|
|
56793
57395
|
}
|
|
56794
57396
|
ctx.body = list;
|
|
56795
57397
|
});
|
|
56796
|
-
router$
|
|
57398
|
+
router$e.post("/handleWebhook", async (ctx) => {
|
|
56797
57399
|
const { data } = ctx.request.body;
|
|
56798
57400
|
const liveList = exports.handler.liveData;
|
|
56799
57401
|
for (const live of liveList) {
|
|
@@ -56809,7 +57411,7 @@ router$d.post("/handleWebhook", async (ctx) => {
|
|
|
56809
57411
|
}
|
|
56810
57412
|
ctx.body = "success";
|
|
56811
57413
|
});
|
|
56812
|
-
router$
|
|
57414
|
+
router$e.post("/webhook", async (ctx) => {
|
|
56813
57415
|
const liveList = exports.handler.liveData;
|
|
56814
57416
|
ctx.body = liveList;
|
|
56815
57417
|
});
|
|
@@ -56819,7 +57421,7 @@ router$d.post("/webhook", async (ctx) => {
|
|
|
56819
57421
|
* 如果不是,检查全局webhook配置,判断是否开启全局开关,判断是否在黑名单,判断配置是否配置了上传预设,上传账号
|
|
56820
57422
|
* 返回{hasError:boolean,errorInfo:string}
|
|
56821
57423
|
*/
|
|
56822
|
-
router$
|
|
57424
|
+
router$e.get("/whyUploadFailed", async (ctx) => {
|
|
56823
57425
|
const { roomId } = ctx.request.query;
|
|
56824
57426
|
if (!roomId) {
|
|
56825
57427
|
ctx.status = 400;
|
|
@@ -56976,7 +57578,7 @@ router$d.get("/whyUploadFailed", async (ctx) => {
|
|
|
56976
57578
|
* @apiSuccess {boolean} needUpdate 是否需要更新
|
|
56977
57579
|
* @apiSuccess {string} [downloadUrl] 下载地址
|
|
56978
57580
|
*/
|
|
56979
|
-
router$
|
|
57581
|
+
router$e.get("/checkUpdate", async (ctx) => {
|
|
56980
57582
|
try {
|
|
56981
57583
|
const res = await fetch("https://githubraw.irenmu.com/renmu123/biliLive-tools/master/package.json");
|
|
56982
57584
|
const data = await res.json();
|
|
@@ -57001,31 +57603,15 @@ router$d.get("/checkUpdate", async (ctx) => {
|
|
|
57001
57603
|
};
|
|
57002
57604
|
}
|
|
57003
57605
|
});
|
|
57004
|
-
/**
|
|
57005
|
-
* @api {get} /common/tempPath 获取缓存文件夹路径
|
|
57006
|
-
* @apiDescription 获取当前配置的缓存文件夹路径
|
|
57007
|
-
* @apiSuccess {string} path 缓存文件夹路径
|
|
57008
|
-
*/
|
|
57009
|
-
router$d.get("/tempPath", async (ctx) => {
|
|
57010
|
-
try {
|
|
57011
|
-
const tempPath = index.getTempPath();
|
|
57012
|
-
ctx.body = tempPath;
|
|
57013
|
-
}
|
|
57014
|
-
catch (error) {
|
|
57015
|
-
console.error("获取缓存路径失败:", error);
|
|
57016
|
-
ctx.status = 500;
|
|
57017
|
-
ctx.body = "获取缓存路径失败";
|
|
57018
|
-
}
|
|
57019
|
-
});
|
|
57020
57606
|
/**
|
|
57021
57607
|
* @api {get} /common/diskSpace 获取磁盘空间信息
|
|
57022
|
-
* @apiDescription
|
|
57608
|
+
* @apiDescription 获取录制文件夹所在磁盘的空间信息
|
|
57023
57609
|
* @apiSuccess {number} total 总空间(GB)
|
|
57024
57610
|
* @apiSuccess {number} free 可用空间(GB)
|
|
57025
57611
|
* @apiSuccess {number} used 已用空间(GB)
|
|
57026
57612
|
* @apiSuccess {number} usedPercentage 使用百分比
|
|
57027
57613
|
*/
|
|
57028
|
-
router$
|
|
57614
|
+
router$e.get("/diskSpace", async (ctx) => {
|
|
57029
57615
|
try {
|
|
57030
57616
|
const config = exports.appConfig.getAll();
|
|
57031
57617
|
const recoderFolder = config?.recorder?.savePath;
|
|
@@ -57059,10 +57645,10 @@ router$d.get("/diskSpace", async (ctx) => {
|
|
|
57059
57645
|
}
|
|
57060
57646
|
});
|
|
57061
57647
|
|
|
57062
|
-
const router$
|
|
57648
|
+
const router$d = new Router$1({
|
|
57063
57649
|
prefix: "/user",
|
|
57064
57650
|
});
|
|
57065
|
-
router$
|
|
57651
|
+
router$d.get("/list", async (ctx) => {
|
|
57066
57652
|
const list = index.biliApi.readUserList();
|
|
57067
57653
|
ctx.body = list.map((item) => {
|
|
57068
57654
|
return {
|
|
@@ -57073,22 +57659,22 @@ router$c.get("/list", async (ctx) => {
|
|
|
57073
57659
|
};
|
|
57074
57660
|
});
|
|
57075
57661
|
});
|
|
57076
|
-
router$
|
|
57662
|
+
router$d.post("/delete", async (ctx) => {
|
|
57077
57663
|
const { uid } = ctx.request.body;
|
|
57078
57664
|
await index.biliApi.deleteUser(uid);
|
|
57079
57665
|
ctx.status = 200;
|
|
57080
57666
|
});
|
|
57081
|
-
router$
|
|
57667
|
+
router$d.post("/update", async (ctx) => {
|
|
57082
57668
|
const { uid } = ctx.request.body;
|
|
57083
57669
|
await index.biliApi.updateUserInfo(uid);
|
|
57084
57670
|
ctx.status = 200;
|
|
57085
57671
|
});
|
|
57086
|
-
router$
|
|
57672
|
+
router$d.post("/update_auth", async (ctx) => {
|
|
57087
57673
|
const { uid } = ctx.request.body;
|
|
57088
57674
|
await index.biliApi.updateAuth(uid);
|
|
57089
57675
|
ctx.status = 200;
|
|
57090
57676
|
});
|
|
57091
|
-
router$
|
|
57677
|
+
router$d.post("/get_cookie", async (ctx) => {
|
|
57092
57678
|
const { uid, timestamp, signature } = ctx.request.body;
|
|
57093
57679
|
const currentTimestamp = Math.floor(Date.now() / 1000);
|
|
57094
57680
|
if (Math.abs(currentTimestamp - timestamp) > 10) {
|
|
@@ -57097,7 +57683,7 @@ router$c.post("/get_cookie", async (ctx) => {
|
|
|
57097
57683
|
return;
|
|
57098
57684
|
}
|
|
57099
57685
|
const secret = "r96gkr8ahc34fsrewr34";
|
|
57100
|
-
const hash = require$$1$
|
|
57686
|
+
const hash = require$$1$3.createHmac("sha256", secret).update(`${uid}${timestamp}`).digest("hex");
|
|
57101
57687
|
if (hash !== signature) {
|
|
57102
57688
|
ctx.status = 400;
|
|
57103
57689
|
ctx.body = "签名无效";
|
|
@@ -57119,11 +57705,11 @@ router$c.post("/get_cookie", async (ctx) => {
|
|
|
57119
57705
|
ctx.body = "获取失败,请重试";
|
|
57120
57706
|
}
|
|
57121
57707
|
});
|
|
57122
|
-
router$
|
|
57708
|
+
router$d.get("/export", async (ctx) => {
|
|
57123
57709
|
const list = index.biliApi.readUserList();
|
|
57124
57710
|
ctx.body = list;
|
|
57125
57711
|
});
|
|
57126
|
-
router$
|
|
57712
|
+
router$d.post("/export_single", async (ctx) => {
|
|
57127
57713
|
const { uid } = ctx.request.body;
|
|
57128
57714
|
const user = index.biliApi.readUser(uid);
|
|
57129
57715
|
if (!user) {
|
|
@@ -57133,7 +57719,7 @@ router$c.post("/export_single", async (ctx) => {
|
|
|
57133
57719
|
}
|
|
57134
57720
|
ctx.body = user;
|
|
57135
57721
|
});
|
|
57136
|
-
router$
|
|
57722
|
+
router$d.post("/import", async (ctx) => {
|
|
57137
57723
|
const { users } = ctx.request.body;
|
|
57138
57724
|
if (!Array.isArray(users)) {
|
|
57139
57725
|
ctx.status = 400;
|
|
@@ -57150,7 +57736,7 @@ router$c.post("/import", async (ctx) => {
|
|
|
57150
57736
|
}
|
|
57151
57737
|
ctx.status = 200;
|
|
57152
57738
|
});
|
|
57153
|
-
router$
|
|
57739
|
+
router$d.post("/import_single", async (ctx) => {
|
|
57154
57740
|
const { user } = ctx.request.body;
|
|
57155
57741
|
if (!user?.mid || !user?.accessToken || !user?.refreshToken || !user?.cookie) {
|
|
57156
57742
|
ctx.status = 400;
|
|
@@ -57161,103 +57747,103 @@ router$c.post("/import_single", async (ctx) => {
|
|
|
57161
57747
|
ctx.status = 200;
|
|
57162
57748
|
});
|
|
57163
57749
|
|
|
57164
|
-
const router$
|
|
57750
|
+
const router$c = new Router$1({
|
|
57165
57751
|
prefix: "/preset",
|
|
57166
57752
|
});
|
|
57167
57753
|
////////////////// 弹幕预设 ///////////////////////////////
|
|
57168
|
-
router$
|
|
57754
|
+
router$c.get("/danmu", async (ctx) => {
|
|
57169
57755
|
const danmuPreset = exports.container.resolve("danmuPreset");
|
|
57170
57756
|
ctx.body = await danmuPreset.list();
|
|
57171
57757
|
});
|
|
57172
|
-
router$
|
|
57758
|
+
router$c.get("/danmu/:id", async (ctx) => {
|
|
57173
57759
|
const danmuPreset = exports.container.resolve("danmuPreset");
|
|
57174
57760
|
ctx.body = await danmuPreset.get(ctx.params.id);
|
|
57175
57761
|
});
|
|
57176
|
-
router$
|
|
57762
|
+
router$c.post("/danmu", async (ctx) => {
|
|
57177
57763
|
const danmuPreset = exports.container.resolve("danmuPreset");
|
|
57178
57764
|
const data = ctx.request.body;
|
|
57179
57765
|
ctx.body = await danmuPreset.save(data);
|
|
57180
57766
|
});
|
|
57181
|
-
router$
|
|
57767
|
+
router$c.del("/danmu/:id", async (ctx) => {
|
|
57182
57768
|
const danmuPreset = exports.container.resolve("danmuPreset");
|
|
57183
57769
|
ctx.body = await danmuPreset.delete(ctx.params.id);
|
|
57184
57770
|
});
|
|
57185
|
-
router$
|
|
57771
|
+
router$c.put("/danmu/:id", async (ctx) => {
|
|
57186
57772
|
const danmuPreset = exports.container.resolve("danmuPreset");
|
|
57187
57773
|
const data = ctx.request.body;
|
|
57188
57774
|
ctx.body = await danmuPreset.save({ ...data, id: ctx.params.id });
|
|
57189
57775
|
});
|
|
57190
57776
|
////////////////// 视频上传预设 ///////////////////////////////
|
|
57191
|
-
router$
|
|
57777
|
+
router$c.get("/video", async (ctx) => {
|
|
57192
57778
|
const preset = exports.container.resolve("videoPreset");
|
|
57193
57779
|
ctx.body = await preset.list();
|
|
57194
57780
|
});
|
|
57195
|
-
router$
|
|
57781
|
+
router$c.get("/video/:id", async (ctx) => {
|
|
57196
57782
|
const preset = exports.container.resolve("videoPreset");
|
|
57197
57783
|
ctx.body = await preset.get(ctx.params.id);
|
|
57198
57784
|
});
|
|
57199
|
-
router$
|
|
57785
|
+
router$c.post("/video", async (ctx) => {
|
|
57200
57786
|
const preset = exports.container.resolve("videoPreset");
|
|
57201
57787
|
const data = ctx.request.body;
|
|
57202
57788
|
data.config = index.omit(data.config, ["dtime"]);
|
|
57203
57789
|
ctx.body = await preset.save(data);
|
|
57204
57790
|
});
|
|
57205
|
-
router$
|
|
57791
|
+
router$c.del("/video/:id", async (ctx) => {
|
|
57206
57792
|
const preset = exports.container.resolve("videoPreset");
|
|
57207
57793
|
ctx.body = await preset.delete(ctx.params.id);
|
|
57208
57794
|
});
|
|
57209
|
-
router$
|
|
57795
|
+
router$c.put("/video/:id", async (ctx) => {
|
|
57210
57796
|
const preset = exports.container.resolve("videoPreset");
|
|
57211
57797
|
const data = ctx.request.body;
|
|
57212
57798
|
data.config = index.omit(data.config, ["dtime"]);
|
|
57213
57799
|
ctx.body = await preset.save({ ...data, id: ctx.params.id });
|
|
57214
57800
|
});
|
|
57215
57801
|
////////////////// ffmpeg预设 ///////////////////////////////
|
|
57216
|
-
router$
|
|
57802
|
+
router$c.get("/ffmpeg", async (ctx) => {
|
|
57217
57803
|
const preset = exports.container.resolve("ffmpegPreset");
|
|
57218
57804
|
ctx.body = await preset.list();
|
|
57219
57805
|
});
|
|
57220
|
-
router$
|
|
57806
|
+
router$c.get("/ffmpeg/options", async (ctx) => {
|
|
57221
57807
|
const preset = exports.container.resolve("ffmpegPreset");
|
|
57222
57808
|
ctx.body = await preset.getFfmpegPresetOptions();
|
|
57223
57809
|
});
|
|
57224
|
-
router$
|
|
57810
|
+
router$c.get("/ffmpeg/:id", async (ctx) => {
|
|
57225
57811
|
const preset = exports.container.resolve("ffmpegPreset");
|
|
57226
57812
|
ctx.body = await preset.get(ctx.params.id);
|
|
57227
57813
|
});
|
|
57228
|
-
router$
|
|
57814
|
+
router$c.post("/ffmpeg", async (ctx) => {
|
|
57229
57815
|
const preset = exports.container.resolve("ffmpegPreset");
|
|
57230
57816
|
const data = ctx.request.body;
|
|
57231
57817
|
ctx.body = await preset.save(data);
|
|
57232
57818
|
});
|
|
57233
|
-
router$
|
|
57819
|
+
router$c.del("/ffmpeg/:id", async (ctx) => {
|
|
57234
57820
|
const preset = exports.container.resolve("ffmpegPreset");
|
|
57235
57821
|
ctx.body = await preset.delete(ctx.params.id);
|
|
57236
57822
|
});
|
|
57237
|
-
router$
|
|
57823
|
+
router$c.put("/ffmpeg/:id", async (ctx) => {
|
|
57238
57824
|
const preset = exports.container.resolve("ffmpegPreset");
|
|
57239
57825
|
const data = ctx.request.body;
|
|
57240
57826
|
ctx.body = await preset.save({ ...data, id: ctx.params.id });
|
|
57241
57827
|
});
|
|
57242
57828
|
////////////////// 字幕样式预设 ///////////////////////////////
|
|
57243
|
-
router$
|
|
57829
|
+
router$c.get("/subtitle-style", async (ctx) => {
|
|
57244
57830
|
const preset = exports.container.resolve("subtitleStylePreset");
|
|
57245
57831
|
ctx.body = await preset.list();
|
|
57246
57832
|
});
|
|
57247
|
-
router$
|
|
57833
|
+
router$c.get("/subtitle-style/:id", async (ctx) => {
|
|
57248
57834
|
const preset = exports.container.resolve("subtitleStylePreset");
|
|
57249
57835
|
ctx.body = await preset.get(ctx.params.id);
|
|
57250
57836
|
});
|
|
57251
|
-
router$
|
|
57837
|
+
router$c.post("/subtitle-style", async (ctx) => {
|
|
57252
57838
|
const preset = exports.container.resolve("subtitleStylePreset");
|
|
57253
57839
|
const data = ctx.request.body;
|
|
57254
57840
|
ctx.body = await preset.save(data);
|
|
57255
57841
|
});
|
|
57256
|
-
router$
|
|
57842
|
+
router$c.del("/subtitle-style/:id", async (ctx) => {
|
|
57257
57843
|
const preset = exports.container.resolve("subtitleStylePreset");
|
|
57258
57844
|
ctx.body = await preset.delete(ctx.params.id);
|
|
57259
57845
|
});
|
|
57260
|
-
router$
|
|
57846
|
+
router$c.put("/subtitle-style/:id", async (ctx) => {
|
|
57261
57847
|
const preset = exports.container.resolve("subtitleStylePreset");
|
|
57262
57848
|
const data = ctx.request.body;
|
|
57263
57849
|
ctx.body = await preset.save({ ...data, id: ctx.params.id });
|
|
@@ -57267,7 +57853,7 @@ var chokidar = {};
|
|
|
57267
57853
|
|
|
57268
57854
|
var utils$7 = {};
|
|
57269
57855
|
|
|
57270
|
-
const path$4 = require$$0$
|
|
57856
|
+
const path$4 = require$$0$7;
|
|
57271
57857
|
const WIN_SLASH$1 = '\\\\/';
|
|
57272
57858
|
const WIN_NO_SLASH$1 = `[^${WIN_SLASH$1}]`;
|
|
57273
57859
|
|
|
@@ -57447,7 +58033,7 @@ var constants$6 = {
|
|
|
57447
58033
|
|
|
57448
58034
|
(function (exports) {
|
|
57449
58035
|
|
|
57450
|
-
const path = require$$0$
|
|
58036
|
+
const path = require$$0$7;
|
|
57451
58037
|
const win32 = process.platform === 'win32';
|
|
57452
58038
|
const {
|
|
57453
58039
|
REGEX_BACKSLASH,
|
|
@@ -58991,7 +59577,7 @@ parse$3.fastpaths = (input, options) => {
|
|
|
58991
59577
|
|
|
58992
59578
|
var parse_1$1 = parse$3;
|
|
58993
59579
|
|
|
58994
|
-
const path$3 = require$$0$
|
|
59580
|
+
const path$3 = require$$0$7;
|
|
58995
59581
|
const scan$2 = scan_1$1;
|
|
58996
59582
|
const parse$2 = parse_1$1;
|
|
58997
59583
|
const utils$4 = utils$7;
|
|
@@ -59336,8 +59922,8 @@ var picomatch$4 = picomatch_1$1;
|
|
|
59336
59922
|
|
|
59337
59923
|
const fs$3 = require$$0$8;
|
|
59338
59924
|
const { Readable } = require$$0$9;
|
|
59339
|
-
const sysPath$3 = require$$0$
|
|
59340
|
-
const { promisify: promisify$3 } = require$$1$
|
|
59925
|
+
const sysPath$3 = require$$0$7;
|
|
59926
|
+
const { promisify: promisify$3 } = require$$1$4;
|
|
59341
59927
|
const picomatch$3 = picomatch$4;
|
|
59342
59928
|
|
|
59343
59929
|
const readdir$1 = promisify$3(fs$3.readdir);
|
|
@@ -59624,7 +60210,7 @@ var anymatch$2 = {exports: {}};
|
|
|
59624
60210
|
|
|
59625
60211
|
var utils$3 = {};
|
|
59626
60212
|
|
|
59627
|
-
const path$2 = require$$0$
|
|
60213
|
+
const path$2 = require$$0$7;
|
|
59628
60214
|
const WIN_SLASH = '\\\\/';
|
|
59629
60215
|
const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
|
|
59630
60216
|
|
|
@@ -59804,7 +60390,7 @@ var constants$3 = {
|
|
|
59804
60390
|
|
|
59805
60391
|
(function (exports) {
|
|
59806
60392
|
|
|
59807
|
-
const path = require$$0$
|
|
60393
|
+
const path = require$$0$7;
|
|
59808
60394
|
const win32 = process.platform === 'win32';
|
|
59809
60395
|
const {
|
|
59810
60396
|
REGEX_BACKSLASH,
|
|
@@ -61348,7 +61934,7 @@ parse$1.fastpaths = (input, options) => {
|
|
|
61348
61934
|
|
|
61349
61935
|
var parse_1 = parse$1;
|
|
61350
61936
|
|
|
61351
|
-
const path$1 = require$$0$
|
|
61937
|
+
const path$1 = require$$0$7;
|
|
61352
61938
|
const scan = scan_1;
|
|
61353
61939
|
const parse = parse_1;
|
|
61354
61940
|
const utils = utils$3;
|
|
@@ -61698,7 +62284,7 @@ var picomatch$1 = picomatch_1;
|
|
|
61698
62284
|
* Released under the MIT License.
|
|
61699
62285
|
*/
|
|
61700
62286
|
|
|
61701
|
-
var normalizePath$
|
|
62287
|
+
var normalizePath$3 = function(path, stripTrailing) {
|
|
61702
62288
|
if (typeof path !== 'string') {
|
|
61703
62289
|
throw new TypeError('expected path to be a string');
|
|
61704
62290
|
}
|
|
@@ -61732,7 +62318,7 @@ var anymatch_1 = anymatch$2.exports;
|
|
|
61732
62318
|
Object.defineProperty(anymatch_1, "__esModule", { value: true });
|
|
61733
62319
|
|
|
61734
62320
|
const picomatch = picomatch$1;
|
|
61735
|
-
const normalizePath$
|
|
62321
|
+
const normalizePath$2 = normalizePath$3;
|
|
61736
62322
|
|
|
61737
62323
|
/**
|
|
61738
62324
|
* @typedef {(testString: string) => boolean} AnymatchFn
|
|
@@ -61776,7 +62362,7 @@ const matchPatterns = (patterns, negPatterns, args, returnIndex) => {
|
|
|
61776
62362
|
throw new TypeError('anymatch: second argument must be a string: got ' +
|
|
61777
62363
|
Object.prototype.toString.call(_path))
|
|
61778
62364
|
}
|
|
61779
|
-
const path = normalizePath$
|
|
62365
|
+
const path = normalizePath$2(_path, false);
|
|
61780
62366
|
|
|
61781
62367
|
for (let index = 0; index < negPatterns.length; index++) {
|
|
61782
62368
|
const nglob = negPatterns[index];
|
|
@@ -62100,7 +62686,7 @@ var require$$0 = [
|
|
|
62100
62686
|
|
|
62101
62687
|
var binaryExtensions$1 = require$$0;
|
|
62102
62688
|
|
|
62103
|
-
const path = require$$0$
|
|
62689
|
+
const path = require$$0$7;
|
|
62104
62690
|
const binaryExtensions = binaryExtensions$1;
|
|
62105
62691
|
|
|
62106
62692
|
const extensions = new Set(binaryExtensions);
|
|
@@ -62111,7 +62697,7 @@ var constants = {};
|
|
|
62111
62697
|
|
|
62112
62698
|
(function (exports) {
|
|
62113
62699
|
|
|
62114
|
-
const {sep} = require$$0$
|
|
62700
|
+
const {sep} = require$$0$7;
|
|
62115
62701
|
const {platform} = process;
|
|
62116
62702
|
const os = require$$1$6;
|
|
62117
62703
|
|
|
@@ -62178,8 +62764,8 @@ var constants = {};
|
|
|
62178
62764
|
} (constants));
|
|
62179
62765
|
|
|
62180
62766
|
const fs$2 = require$$0$8;
|
|
62181
|
-
const sysPath$2 = require$$0$
|
|
62182
|
-
const { promisify: promisify$2 } = require$$1$
|
|
62767
|
+
const sysPath$2 = require$$0$7;
|
|
62768
|
+
const { promisify: promisify$2 } = require$$1$4;
|
|
62183
62769
|
const isBinaryPath = isBinaryPath$1;
|
|
62184
62770
|
const {
|
|
62185
62771
|
isWindows: isWindows$1,
|
|
@@ -62829,8 +63415,8 @@ var nodefsHandler = NodeFsHandler$1;
|
|
|
62829
63415
|
var fseventsHandler = {exports: {}};
|
|
62830
63416
|
|
|
62831
63417
|
const fs$1 = require$$0$8;
|
|
62832
|
-
const sysPath$1 = require$$0$
|
|
62833
|
-
const { promisify: promisify$1 } = require$$1$
|
|
63418
|
+
const sysPath$1 = require$$0$7;
|
|
63419
|
+
const { promisify: promisify$1 } = require$$1$4;
|
|
62834
63420
|
|
|
62835
63421
|
let fsevents;
|
|
62836
63422
|
try {
|
|
@@ -63355,16 +63941,16 @@ fseventsHandler.exports.canUse = canUse;
|
|
|
63355
63941
|
|
|
63356
63942
|
var fseventsHandlerExports = fseventsHandler.exports;
|
|
63357
63943
|
|
|
63358
|
-
const { EventEmitter } = require$$0$
|
|
63944
|
+
const { EventEmitter } = require$$0$4;
|
|
63359
63945
|
const fs = require$$0$8;
|
|
63360
|
-
const sysPath = require$$0$
|
|
63361
|
-
const { promisify } = require$$1$
|
|
63946
|
+
const sysPath = require$$0$7;
|
|
63947
|
+
const { promisify } = require$$1$4;
|
|
63362
63948
|
const readdirp = readdirp_1;
|
|
63363
63949
|
const anymatch = anymatchExports.default;
|
|
63364
63950
|
const globParent = index.globParent;
|
|
63365
63951
|
const isGlob = index.isGlob;
|
|
63366
63952
|
const braces = index.braces_1;
|
|
63367
|
-
const normalizePath = normalizePath$
|
|
63953
|
+
const normalizePath$1 = normalizePath$3;
|
|
63368
63954
|
|
|
63369
63955
|
const NodeFsHandler = nodefsHandler;
|
|
63370
63956
|
const FsEventsHandler = fseventsHandlerExports;
|
|
@@ -63772,7 +64358,7 @@ add(paths_, _origAdd, _internal) {
|
|
|
63772
64358
|
if (disableGlobbing || !isGlob(path)) {
|
|
63773
64359
|
return absPath;
|
|
63774
64360
|
}
|
|
63775
|
-
return normalizePath(absPath);
|
|
64361
|
+
return normalizePath$1(absPath);
|
|
63776
64362
|
});
|
|
63777
64363
|
}
|
|
63778
64364
|
|
|
@@ -64903,10 +65489,10 @@ class FFmpegWhisperASR {
|
|
|
64903
65489
|
throw new Error(`音频文件不存在: ${filePath}`);
|
|
64904
65490
|
}
|
|
64905
65491
|
// 创建临时目录存放结果
|
|
64906
|
-
const tempDir = require$$0$
|
|
65492
|
+
const tempDir = require$$0$7.join(require$$1$6.tmpdir(), "whisper-asr");
|
|
64907
65493
|
await index.fs.ensureDir(tempDir);
|
|
64908
65494
|
// 生成唯一的输出文件名
|
|
64909
|
-
const outputFile = require$$0$
|
|
65495
|
+
const outputFile = require$$0$7.join(tempDir, `${v4()}.json`);
|
|
64910
65496
|
try {
|
|
64911
65497
|
// 执行 ffmpeg 命令
|
|
64912
65498
|
await this.executeFFmpeg(filePath, outputFile);
|
|
@@ -65090,19 +65676,22 @@ class BCutASRAdapter {
|
|
|
65090
65676
|
async recognize() {
|
|
65091
65677
|
throw new Error("B接口 ASR 不支持识别 URL,请使用 recognizeLocalFile");
|
|
65092
65678
|
}
|
|
65093
|
-
async recognizeLocalFile(filePath) {
|
|
65679
|
+
async recognizeLocalFile(filePath, opts) {
|
|
65094
65680
|
// 这里直接返回一个模拟结果,实际使用时需要替换为调用 B接口 ASR 的代码
|
|
65095
65681
|
const asr = new index.BcutASR(filePath);
|
|
65096
65682
|
const result = await asr.recognize();
|
|
65097
65683
|
const data = result.getRawData();
|
|
65098
|
-
return this.transformBCutResult(data);
|
|
65684
|
+
return this.transformBCutResult(data, opts);
|
|
65099
65685
|
}
|
|
65100
65686
|
/**
|
|
65101
65687
|
* 转换 B接口 ASR 格式为标准格式
|
|
65102
65688
|
*/
|
|
65103
|
-
transformBCutResult(data) {
|
|
65104
|
-
|
|
65105
|
-
|
|
65689
|
+
transformBCutResult(data, opts) {
|
|
65690
|
+
let list = data.utterances;
|
|
65691
|
+
if (opts?.filterMusic) {
|
|
65692
|
+
list = list.filter((s) => s.music <= 0.9); // 过滤掉标记为音乐的段落
|
|
65693
|
+
}
|
|
65694
|
+
let segments = list.map((utterance, index) => ({
|
|
65106
65695
|
id: index,
|
|
65107
65696
|
start: utterance.start_time / 1000,
|
|
65108
65697
|
end: utterance.end_time / 1000,
|
|
@@ -65260,9 +65849,9 @@ function createASRProvider(modelId) {
|
|
|
65260
65849
|
* @param modelId 模型id
|
|
65261
65850
|
* @returns
|
|
65262
65851
|
*/
|
|
65263
|
-
function recognize$1(file, modelId) {
|
|
65852
|
+
function recognize$1(file, modelId, opts) {
|
|
65264
65853
|
const asrProvider = createASRProvider(modelId);
|
|
65265
|
-
return asrProvider.recognizeLocalFile(file);
|
|
65854
|
+
return asrProvider.recognizeLocalFile(file, opts);
|
|
65266
65855
|
}
|
|
65267
65856
|
|
|
65268
65857
|
const default_format = 'RFC3986';
|
|
@@ -72119,7 +72708,7 @@ class DecodedMessage {
|
|
|
72119
72708
|
if (!uri.startsWith(DATA_URI_PREFIX)) {
|
|
72120
72709
|
throw new Error('assert 4');
|
|
72121
72710
|
}
|
|
72122
|
-
return this.decodeFromBinary(require$$0$
|
|
72711
|
+
return this.decodeFromBinary(require$$0$6.Buffer.from(uri.replace(DATA_URI_PREFIX, ''), 'base64'));
|
|
72123
72712
|
}
|
|
72124
72713
|
encodeToBinary() {
|
|
72125
72714
|
const header = {
|
|
@@ -72170,7 +72759,7 @@ class DecodedMessage {
|
|
|
72170
72759
|
}
|
|
72171
72760
|
encodeToUri() {
|
|
72172
72761
|
const bin = this.encodeToBinary();
|
|
72173
|
-
return DATA_URI_PREFIX + require$$0$
|
|
72762
|
+
return DATA_URI_PREFIX + require$$0$6.Buffer.from(bin).toString('base64');
|
|
72174
72763
|
}
|
|
72175
72764
|
}
|
|
72176
72765
|
|
|
@@ -76657,13 +77246,13 @@ async function songRecognize(file, audioStartTime = 0) {
|
|
|
76657
77246
|
};
|
|
76658
77247
|
}
|
|
76659
77248
|
|
|
76660
|
-
const router$
|
|
77249
|
+
const router$b = new Router$1({
|
|
76661
77250
|
prefix: "/sse",
|
|
76662
77251
|
});
|
|
76663
77252
|
/**
|
|
76664
77253
|
* 流式查询日志
|
|
76665
77254
|
*/
|
|
76666
|
-
router$
|
|
77255
|
+
router$b.get("/streamLogs", sse({
|
|
76667
77256
|
maxClients: 5000,
|
|
76668
77257
|
pingInterval: 60 * 60 * 1000,
|
|
76669
77258
|
}), async (ctx) => {
|
|
@@ -76702,7 +77291,7 @@ router$a.get("/streamLogs", sse({
|
|
|
76702
77291
|
/**
|
|
76703
77292
|
* 获取弹幕流
|
|
76704
77293
|
*/
|
|
76705
|
-
router$
|
|
77294
|
+
router$b.get("/recorder/danma", sse({
|
|
76706
77295
|
maxClients: 5000,
|
|
76707
77296
|
pingInterval: 30000,
|
|
76708
77297
|
}), async (ctx) => {
|
|
@@ -76715,7 +77304,7 @@ router$a.get("/recorder/danma", sse({
|
|
|
76715
77304
|
}
|
|
76716
77305
|
});
|
|
76717
77306
|
});
|
|
76718
|
-
router$
|
|
77307
|
+
router$b.get("/task/runningNum", sse({
|
|
76719
77308
|
maxClients: 5000,
|
|
76720
77309
|
pingInterval: 30000,
|
|
76721
77310
|
}), async (ctx) => {
|
|
@@ -76748,7 +77337,7 @@ router$a.get("/task/runningNum", sse({
|
|
|
76748
77337
|
/**
|
|
76749
77338
|
* 波形分析进度流
|
|
76750
77339
|
*/
|
|
76751
|
-
router$
|
|
77340
|
+
router$b.get("/analyzerWaveform", sse({
|
|
76752
77341
|
maxClients: 100,
|
|
76753
77342
|
pingInterval: 30000,
|
|
76754
77343
|
}), async (ctx) => {
|
|
@@ -76807,9 +77396,256 @@ router$a.get("/analyzerWaveform", sse({
|
|
|
76807
77396
|
});
|
|
76808
77397
|
});
|
|
76809
77398
|
|
|
76810
|
-
const
|
|
77399
|
+
const UNKNOWN_LIVE_ID = "__unknown_live_id__";
|
|
77400
|
+
const getRecordDuration = (record) => {
|
|
77401
|
+
if (record.video_duration && record.video_duration > 0) {
|
|
77402
|
+
return record.video_duration;
|
|
77403
|
+
}
|
|
77404
|
+
if (record.record_end_time && record.record_end_time > record.record_start_time) {
|
|
77405
|
+
return (record.record_end_time - record.record_start_time) / 1000;
|
|
77406
|
+
}
|
|
77407
|
+
return 0;
|
|
77408
|
+
};
|
|
77409
|
+
const toSessionKey = (record) => record.live_id || UNKNOWN_LIVE_ID;
|
|
77410
|
+
const toSessionCard = (records) => {
|
|
77411
|
+
const sortedRecords = [...records].sort((left, right) => right.record_start_time - left.record_start_time);
|
|
77412
|
+
const latestRecord = sortedRecords[0] || null;
|
|
77413
|
+
const earliestLiveStart = records
|
|
77414
|
+
.map((item) => item.live_start_time)
|
|
77415
|
+
.filter((item) => typeof item === "number" && item > 0)
|
|
77416
|
+
.sort((left, right) => left - right)[0];
|
|
77417
|
+
const earliestRecordSTart = records
|
|
77418
|
+
.map((item) => item.record_start_time)
|
|
77419
|
+
.filter((item) => typeof item === "number" && item > 0)
|
|
77420
|
+
.sort((left, right) => left - right)[0];
|
|
77421
|
+
return {
|
|
77422
|
+
sessionKey: toSessionKey(records[0]),
|
|
77423
|
+
liveId: records[0].live_id || null,
|
|
77424
|
+
displayLiveId: records[0].live_id || "未识别场次",
|
|
77425
|
+
title: latestRecord?.title || records[0].title || "未命名场次",
|
|
77426
|
+
liveStartTime: earliestLiveStart || null,
|
|
77427
|
+
recordStartTime: earliestRecordSTart || null,
|
|
77428
|
+
lastRecordTime: latestRecord?.record_start_time || null,
|
|
77429
|
+
clipCount: records.length,
|
|
77430
|
+
totalDuration: records.reduce((total, item) => total + getRecordDuration(item), 0),
|
|
77431
|
+
totalDanmaNum: records.reduce((total, item) => total + (item.danma_num || 0), 0),
|
|
77432
|
+
totalInteractNum: records.reduce((total, item) => total + (item.interact_num || 0), 0),
|
|
77433
|
+
clips: sortedRecords.map((item) => ({
|
|
77434
|
+
id: item.id,
|
|
77435
|
+
title: item.title,
|
|
77436
|
+
live_start_time: item.live_start_time,
|
|
77437
|
+
record_start_time: item.record_start_time,
|
|
77438
|
+
record_end_time: item.record_end_time,
|
|
77439
|
+
video_file: item.video_file,
|
|
77440
|
+
video_filename: item.video_filename,
|
|
77441
|
+
video_duration: item.video_duration,
|
|
77442
|
+
danma_num: item.danma_num,
|
|
77443
|
+
interact_num: item.interact_num,
|
|
77444
|
+
quick_hash: item.quick_hash,
|
|
77445
|
+
})),
|
|
77446
|
+
};
|
|
77447
|
+
};
|
|
77448
|
+
const emptySummary = () => ({
|
|
77449
|
+
sessionCount: 0,
|
|
77450
|
+
clipCount: 0,
|
|
77451
|
+
totalDuration: 0,
|
|
77452
|
+
totalDanmaNum: 0,
|
|
77453
|
+
totalInteractNum: 0,
|
|
77454
|
+
lastRecordTime: null,
|
|
77455
|
+
});
|
|
77456
|
+
function queryStreamerDetail(args) {
|
|
77457
|
+
const page = Number(args.page) > 0 ? Number(args.page) : 1;
|
|
77458
|
+
const pageSize = Number(args.pageSize) > 0 ? Number(args.pageSize) : 10;
|
|
77459
|
+
const streamer = index.streamerService.query({ room_id: args.room_id, platform: args.platform }) || null;
|
|
77460
|
+
if (!streamer) {
|
|
77461
|
+
return {
|
|
77462
|
+
streamer: null,
|
|
77463
|
+
summary: emptySummary(),
|
|
77464
|
+
pagination: {
|
|
77465
|
+
total: 0,
|
|
77466
|
+
page,
|
|
77467
|
+
pageSize,
|
|
77468
|
+
},
|
|
77469
|
+
data: [],
|
|
77470
|
+
};
|
|
77471
|
+
}
|
|
77472
|
+
const records = index.recordHistoryService.list({ streamer_id: streamer.id }).filter((item) => {
|
|
77473
|
+
if (args.startTime && item.record_start_time < args.startTime) {
|
|
77474
|
+
return false;
|
|
77475
|
+
}
|
|
77476
|
+
if (args.endTime && item.record_start_time > args.endTime) {
|
|
77477
|
+
return false;
|
|
77478
|
+
}
|
|
77479
|
+
return true;
|
|
77480
|
+
});
|
|
77481
|
+
const groupedRecords = records.reduce((result, item) => {
|
|
77482
|
+
const sessionKey = toSessionKey(item);
|
|
77483
|
+
const currentValue = result.get(sessionKey) || [];
|
|
77484
|
+
currentValue.push(item);
|
|
77485
|
+
result.set(sessionKey, currentValue);
|
|
77486
|
+
return result;
|
|
77487
|
+
}, new Map());
|
|
77488
|
+
const sessionCards = Array.from(groupedRecords.values())
|
|
77489
|
+
.map((items) => toSessionCard(items))
|
|
77490
|
+
.sort((left, right) => (right.lastRecordTime || 0) - (left.lastRecordTime || 0));
|
|
77491
|
+
const startIndex = (page - 1) * pageSize;
|
|
77492
|
+
const pagedCards = sessionCards.slice(startIndex, startIndex + pageSize);
|
|
77493
|
+
return {
|
|
77494
|
+
streamer,
|
|
77495
|
+
summary: {
|
|
77496
|
+
sessionCount: sessionCards.length,
|
|
77497
|
+
clipCount: records.length,
|
|
77498
|
+
totalDuration: sessionCards.reduce((total, item) => total + item.totalDuration, 0),
|
|
77499
|
+
totalDanmaNum: sessionCards.reduce((total, item) => total + item.totalDanmaNum, 0),
|
|
77500
|
+
totalInteractNum: sessionCards.reduce((total, item) => total + item.totalInteractNum, 0),
|
|
77501
|
+
lastRecordTime: sessionCards[0]?.lastRecordTime || null,
|
|
77502
|
+
},
|
|
77503
|
+
pagination: {
|
|
77504
|
+
total: sessionCards.length,
|
|
77505
|
+
page,
|
|
77506
|
+
pageSize,
|
|
77507
|
+
},
|
|
77508
|
+
data: pagedCards,
|
|
77509
|
+
};
|
|
77510
|
+
}
|
|
77511
|
+
var streamerDetailService = {
|
|
77512
|
+
queryStreamerDetail,
|
|
77513
|
+
};
|
|
77514
|
+
|
|
77515
|
+
const router$a = new Router$1({
|
|
76811
77516
|
prefix: "/recorder",
|
|
76812
77517
|
});
|
|
77518
|
+
const DANMA_TEST_WS_PATH = "/recorder/ws/danma-test";
|
|
77519
|
+
const danmaTestWSS = new WebSocketServer$1({ noServer: true });
|
|
77520
|
+
const parsePositiveNumber = (value) => {
|
|
77521
|
+
if (value === null)
|
|
77522
|
+
return null;
|
|
77523
|
+
const parsed = Number(value);
|
|
77524
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
77525
|
+
return null;
|
|
77526
|
+
}
|
|
77527
|
+
return parsed;
|
|
77528
|
+
};
|
|
77529
|
+
const getRawDataSize = (data) => {
|
|
77530
|
+
if (typeof data === "string") {
|
|
77531
|
+
return Buffer.byteLength(data);
|
|
77532
|
+
}
|
|
77533
|
+
if (Array.isArray(data)) {
|
|
77534
|
+
return data.reduce((total, chunk) => total + chunk.byteLength, 0);
|
|
77535
|
+
}
|
|
77536
|
+
if (data instanceof ArrayBuffer) {
|
|
77537
|
+
return data.byteLength;
|
|
77538
|
+
}
|
|
77539
|
+
if (ArrayBuffer.isView(data)) {
|
|
77540
|
+
return data.byteLength;
|
|
77541
|
+
}
|
|
77542
|
+
return 0;
|
|
77543
|
+
};
|
|
77544
|
+
const closeWebSocket = (socket, code = 1011, reason = "test close") => {
|
|
77545
|
+
if (socket.readyState === socket.OPEN || socket.readyState === socket.CLOSING) {
|
|
77546
|
+
socket.close(code, reason);
|
|
77547
|
+
}
|
|
77548
|
+
};
|
|
77549
|
+
danmaTestWSS.on("connection", (socket, request) => {
|
|
77550
|
+
const url = new URL(request.url ?? DANMA_TEST_WS_PATH, "http://127.0.0.1");
|
|
77551
|
+
const mode = url.searchParams.get("mode") ?? "hold";
|
|
77552
|
+
const sendTextAfterMs = parsePositiveNumber(url.searchParams.get("sendTextAfterMs"));
|
|
77553
|
+
const closeAfterMs = parsePositiveNumber(url.searchParams.get("closeAfterMs"));
|
|
77554
|
+
const destroyAfterMs = parsePositiveNumber(url.searchParams.get("destroyAfterMs"));
|
|
77555
|
+
const closeOnMessageCount = parsePositiveNumber(url.searchParams.get("closeOnMessageCount"));
|
|
77556
|
+
const destroyOnMessageCount = parsePositiveNumber(url.searchParams.get("destroyOnMessageCount"));
|
|
77557
|
+
index.logObj.info("[danma-test-ws] connected", {
|
|
77558
|
+
path: url.pathname,
|
|
77559
|
+
search: url.search,
|
|
77560
|
+
mode,
|
|
77561
|
+
closeAfterMs,
|
|
77562
|
+
destroyAfterMs,
|
|
77563
|
+
closeOnMessageCount,
|
|
77564
|
+
destroyOnMessageCount,
|
|
77565
|
+
sendTextAfterMs,
|
|
77566
|
+
remoteAddress: request.socket.remoteAddress,
|
|
77567
|
+
remotePort: request.socket.remotePort,
|
|
77568
|
+
});
|
|
77569
|
+
let messageCount = 0;
|
|
77570
|
+
let closeTimer = null;
|
|
77571
|
+
let destroyTimer = null;
|
|
77572
|
+
let sendTextTimer = null;
|
|
77573
|
+
const cleanup = () => {
|
|
77574
|
+
if (closeTimer) {
|
|
77575
|
+
clearTimeout(closeTimer);
|
|
77576
|
+
closeTimer = null;
|
|
77577
|
+
}
|
|
77578
|
+
if (destroyTimer) {
|
|
77579
|
+
clearTimeout(destroyTimer);
|
|
77580
|
+
destroyTimer = null;
|
|
77581
|
+
}
|
|
77582
|
+
if (sendTextTimer) {
|
|
77583
|
+
clearTimeout(sendTextTimer);
|
|
77584
|
+
sendTextTimer = null;
|
|
77585
|
+
}
|
|
77586
|
+
};
|
|
77587
|
+
socket.on("message", (data, isBinary) => {
|
|
77588
|
+
messageCount += 1;
|
|
77589
|
+
index.logObj.info("[danma-test-ws] message", {
|
|
77590
|
+
messageCount,
|
|
77591
|
+
isBinary,
|
|
77592
|
+
size: getRawDataSize(data),
|
|
77593
|
+
});
|
|
77594
|
+
if (closeOnMessageCount != null && messageCount >= closeOnMessageCount) {
|
|
77595
|
+
index.logObj.info("[danma-test-ws] close on message count", { messageCount });
|
|
77596
|
+
closeWebSocket(socket, 1011, "close on message count");
|
|
77597
|
+
return;
|
|
77598
|
+
}
|
|
77599
|
+
if (destroyOnMessageCount != null && messageCount >= destroyOnMessageCount) {
|
|
77600
|
+
index.logObj.info("[danma-test-ws] destroy on message count", { messageCount });
|
|
77601
|
+
socket.terminate();
|
|
77602
|
+
}
|
|
77603
|
+
});
|
|
77604
|
+
socket.on("close", (code, reason) => {
|
|
77605
|
+
index.logObj.info("[danma-test-ws] closed", {
|
|
77606
|
+
code,
|
|
77607
|
+
reason: reason.toString(),
|
|
77608
|
+
messageCount,
|
|
77609
|
+
});
|
|
77610
|
+
cleanup();
|
|
77611
|
+
});
|
|
77612
|
+
socket.on("error", (error) => {
|
|
77613
|
+
index.logObj.error("[danma-test-ws] socket error", error);
|
|
77614
|
+
cleanup();
|
|
77615
|
+
});
|
|
77616
|
+
if (mode === "close-immediately") {
|
|
77617
|
+
index.logObj.info("[danma-test-ws] close immediately");
|
|
77618
|
+
closeTimer = setTimeout(() => closeWebSocket(socket, 1011, "close immediately"), 0);
|
|
77619
|
+
return;
|
|
77620
|
+
}
|
|
77621
|
+
if (mode === "destroy-immediately") {
|
|
77622
|
+
index.logObj.info("[danma-test-ws] destroy immediately");
|
|
77623
|
+
destroyTimer = setTimeout(() => socket.terminate(), 0);
|
|
77624
|
+
return;
|
|
77625
|
+
}
|
|
77626
|
+
if (closeAfterMs != null) {
|
|
77627
|
+
index.logObj.info("[danma-test-ws] close after delay", { closeAfterMs });
|
|
77628
|
+
closeTimer = setTimeout(() => closeWebSocket(socket, 1011, "close after delay"), closeAfterMs);
|
|
77629
|
+
}
|
|
77630
|
+
if (destroyAfterMs != null) {
|
|
77631
|
+
index.logObj.info("[danma-test-ws] destroy after delay", { destroyAfterMs });
|
|
77632
|
+
destroyTimer = setTimeout(() => socket.terminate(), destroyAfterMs);
|
|
77633
|
+
}
|
|
77634
|
+
if (sendTextAfterMs != null) {
|
|
77635
|
+
index.logObj.info("[danma-test-ws] send text after delay", { sendTextAfterMs });
|
|
77636
|
+
sendTextTimer = setTimeout(() => {
|
|
77637
|
+
if (socket.readyState === socket.OPEN) {
|
|
77638
|
+
socket.send(`Hello! This is a test WebSocket connection. Mode: ${mode}`);
|
|
77639
|
+
}
|
|
77640
|
+
}, sendTextAfterMs);
|
|
77641
|
+
}
|
|
77642
|
+
});
|
|
77643
|
+
const getSingleQueryValue = (value) => {
|
|
77644
|
+
if (Array.isArray(value)) {
|
|
77645
|
+
return value[0];
|
|
77646
|
+
}
|
|
77647
|
+
return value;
|
|
77648
|
+
};
|
|
76813
77649
|
/**
|
|
76814
77650
|
* 录制任务相关接口
|
|
76815
77651
|
* @route GET /recorder/list
|
|
@@ -76823,12 +77659,64 @@ const router$9 = new Router$1({
|
|
|
76823
77659
|
* @param sortDirection 排序方向 asc: 升序 desc: 降序
|
|
76824
77660
|
* @returns 录制任务列表
|
|
76825
77661
|
*/
|
|
76826
|
-
router$
|
|
77662
|
+
router$a.get("/list", async (ctx) => {
|
|
76827
77663
|
const query = ctx.request.query;
|
|
76828
77664
|
ctx.body = { payload: await recorderService.getRecorders(query) };
|
|
76829
77665
|
});
|
|
76830
|
-
router$
|
|
76831
|
-
const
|
|
77666
|
+
router$a.get("/detail", async (ctx) => {
|
|
77667
|
+
const recorderId = getSingleQueryValue(ctx.request.query.recorderId);
|
|
77668
|
+
const page = getSingleQueryValue(ctx.request.query.page);
|
|
77669
|
+
const pageSize = getSingleQueryValue(ctx.request.query.pageSize);
|
|
77670
|
+
const startTime = getSingleQueryValue(ctx.request.query.startTime);
|
|
77671
|
+
const endTime = getSingleQueryValue(ctx.request.query.endTime);
|
|
77672
|
+
if (!recorderId) {
|
|
77673
|
+
ctx.status = 400;
|
|
77674
|
+
ctx.body = {
|
|
77675
|
+
message: "recorderId 不能为空",
|
|
77676
|
+
};
|
|
77677
|
+
return;
|
|
77678
|
+
}
|
|
77679
|
+
const recorder = recorderService.getRecorder({ id: recorderId });
|
|
77680
|
+
const recorderInfo = recorderService.getRecorderInfo({ id: recorderId });
|
|
77681
|
+
if (!recorder) {
|
|
77682
|
+
ctx.status = 404;
|
|
77683
|
+
ctx.body = {
|
|
77684
|
+
message: "录制器不存在",
|
|
77685
|
+
};
|
|
77686
|
+
return;
|
|
77687
|
+
}
|
|
77688
|
+
const payload = streamerDetailService.queryStreamerDetail({
|
|
77689
|
+
room_id: recorder.channelId,
|
|
77690
|
+
platform: recorder.providerId,
|
|
77691
|
+
page: page ? Number(page) : undefined,
|
|
77692
|
+
pageSize: pageSize ? Number(pageSize) : undefined,
|
|
77693
|
+
startTime: startTime ? Number(startTime) : undefined,
|
|
77694
|
+
endTime: endTime ? Number(endTime) : undefined,
|
|
77695
|
+
});
|
|
77696
|
+
ctx.body = {
|
|
77697
|
+
payload: {
|
|
77698
|
+
...payload,
|
|
77699
|
+
recorderInfo,
|
|
77700
|
+
},
|
|
77701
|
+
};
|
|
77702
|
+
});
|
|
77703
|
+
router$a.get("/ws/danma-test", async (ctx) => {
|
|
77704
|
+
ctx.status = 426;
|
|
77705
|
+
ctx.body = {
|
|
77706
|
+
message: "请使用 WebSocket 连接此地址",
|
|
77707
|
+
wsPath: DANMA_TEST_WS_PATH,
|
|
77708
|
+
usage: {
|
|
77709
|
+
mode: ["hold", "close-immediately", "destroy-immediately", "reject-upgrade"],
|
|
77710
|
+
closeAfterMs: "连接建立后延迟关闭",
|
|
77711
|
+
destroyAfterMs: "连接建立后延迟强制断开",
|
|
77712
|
+
closeOnMessageCount: "收到指定数量消息后关闭",
|
|
77713
|
+
destroyOnMessageCount: "收到指定数量消息后强制断开",
|
|
77714
|
+
sendTextAfterMs: "连接建立后延迟发送一条文本消息,默认不发送",
|
|
77715
|
+
},
|
|
77716
|
+
};
|
|
77717
|
+
});
|
|
77718
|
+
router$a.post("/add", async (ctx) => {
|
|
77719
|
+
const args = index.pick((ctx.request.body ?? {}), "providerId", "channelId", "remarks", "disableAutoCheck", "quality", "streamPriorities", "sourcePriorities", "extra", "noGlobalFollowFields", "line", "disableProvideCommentsWhenRecording", "saveGiftDanma", "saveSCDanma", "segment", "sendToWebhook", "uid", "saveCover", "convert2Mp4", "qualityRetry", "formatName", "useM3U8Proxy", "customHost", "codecName", "titleKeywords", "liveStartNotification", "liveEndNotification", "weight", "source", "videoFormat", "recorderType", "cookie", "doubleScreen", "onlyAudio", "useServerTimestamp", "handleTime", "debugLevel", "api");
|
|
76832
77720
|
const data = await recorderService.addRecorder(args);
|
|
76833
77721
|
ctx.body = { payload: data };
|
|
76834
77722
|
});
|
|
@@ -76838,13 +77726,13 @@ router$9.post("/add", async (ctx) => {
|
|
|
76838
77726
|
* @param recorderId 直播间ID
|
|
76839
77727
|
* @returns 录制器配置信息
|
|
76840
77728
|
*/
|
|
76841
|
-
router$
|
|
77729
|
+
router$a.get("/:id", (ctx) => {
|
|
76842
77730
|
const { id } = ctx.params;
|
|
76843
77731
|
ctx.body = { payload: recorderService.getRecorder({ id }) };
|
|
76844
77732
|
});
|
|
76845
|
-
router$
|
|
77733
|
+
router$a.put("/:id", (ctx) => {
|
|
76846
77734
|
const { id } = ctx.params;
|
|
76847
|
-
const patch = index.pick(ctx.request.body, "remarks", "disableAutoCheck", "quality", "streamPriorities", "sourcePriorities", "noGlobalFollowFields", "line", "disableProvideCommentsWhenRecording", "saveGiftDanma", "saveSCDanma", "saveCover", "segment", "sendToWebhook", "uid", "qualityRetry", "formatName", "useM3U8Proxy", "customHost", "codecName", "titleKeywords", "liveStartNotification", "liveEndNotification", "weight", "source", "videoFormat", "recorderType", "cookie", "doubleScreen", "onlyAudio", "useServerTimestamp", "handleTime", "debugLevel", "api");
|
|
77735
|
+
const patch = index.pick(ctx.request.body, "remarks", "disableAutoCheck", "quality", "streamPriorities", "sourcePriorities", "noGlobalFollowFields", "line", "disableProvideCommentsWhenRecording", "saveGiftDanma", "saveSCDanma", "saveCover", "segment", "sendToWebhook", "uid", "qualityRetry", "formatName", "useM3U8Proxy", "customHost", "codecName", "titleKeywords", "liveStartNotification", "liveEndNotification", "weight", "source", "videoFormat", "recorderType", "cookie", "doubleScreen", "onlyAudio", "useServerTimestamp", "handleTime", "debugLevel", "convert2Mp4", "api");
|
|
76848
77736
|
ctx.body = { payload: recorderService.updateRecorder({ id, ...patch }) };
|
|
76849
77737
|
});
|
|
76850
77738
|
/**
|
|
@@ -76854,7 +77742,7 @@ router$9.put("/:id", (ctx) => {
|
|
|
76854
77742
|
* @param removeHistory 是否删除录制历史,默认false
|
|
76855
77743
|
* @returns null
|
|
76856
77744
|
*/
|
|
76857
|
-
router$
|
|
77745
|
+
router$a.delete("/:id", (ctx) => {
|
|
76858
77746
|
const { id } = ctx.params;
|
|
76859
77747
|
const { removeHistory } = ctx.request.query;
|
|
76860
77748
|
ctx.body = {
|
|
@@ -76867,7 +77755,7 @@ router$9.delete("/:id", (ctx) => {
|
|
|
76867
77755
|
* @param recorderId 直播间ID
|
|
76868
77756
|
* @returns 录制任务信息
|
|
76869
77757
|
*/
|
|
76870
|
-
router$
|
|
77758
|
+
router$a.post("/:id/start_record", async (ctx) => {
|
|
76871
77759
|
const { id } = ctx.params;
|
|
76872
77760
|
ctx.body = { payload: await recorderService.startRecord({ id }) };
|
|
76873
77761
|
});
|
|
@@ -76877,7 +77765,7 @@ router$9.post("/:id/start_record", async (ctx) => {
|
|
|
76877
77765
|
* @param recorderId 直播间ID
|
|
76878
77766
|
* @returns 录制任务信息
|
|
76879
77767
|
*/
|
|
76880
|
-
router$
|
|
77768
|
+
router$a.post("/:id/stop_record", async (ctx) => {
|
|
76881
77769
|
const { id } = ctx.params;
|
|
76882
77770
|
ctx.body = { payload: await recorderService.stopRecord({ id }) };
|
|
76883
77771
|
});
|
|
@@ -76887,17 +77775,27 @@ router$9.post("/:id/stop_record", async (ctx) => {
|
|
|
76887
77775
|
* @param recorderId 直播间ID
|
|
76888
77776
|
* @returns 录制任务信息
|
|
76889
77777
|
*/
|
|
76890
|
-
router$
|
|
77778
|
+
router$a.post("/:id/cut", async (ctx) => {
|
|
76891
77779
|
const { id } = ctx.params;
|
|
76892
77780
|
ctx.body = { payload: await recorderService.cutRecord({ id }) };
|
|
76893
77781
|
});
|
|
77782
|
+
/**
|
|
77783
|
+
* 获取最近录制文件所在文件夹
|
|
77784
|
+
* @route GET /recorder/:recorderId/recent-record-folder
|
|
77785
|
+
* @param recorderId 直播间ID
|
|
77786
|
+
* @returns 最近录制文件目录
|
|
77787
|
+
*/
|
|
77788
|
+
router$a.get("/:id/recent-record-folder", async (ctx) => {
|
|
77789
|
+
const { id } = ctx.params;
|
|
77790
|
+
ctx.body = { payload: await recorderService.getRecentRecordFolder({ id }) };
|
|
77791
|
+
});
|
|
76894
77792
|
/**
|
|
76895
77793
|
* 批量开始录制
|
|
76896
77794
|
* @route POST /recorder/manager/batch_start_record
|
|
76897
77795
|
* @param ids 直播间ID列表
|
|
76898
77796
|
* @returns 批量操作结果
|
|
76899
77797
|
*/
|
|
76900
|
-
router$
|
|
77798
|
+
router$a.post("/manager/batch_start_record", async (ctx) => {
|
|
76901
77799
|
const { ids } = ctx.request.body;
|
|
76902
77800
|
ctx.body = { payload: await recorderService.batchStartRecord(ids) };
|
|
76903
77801
|
});
|
|
@@ -76907,7 +77805,7 @@ router$9.post("/manager/batch_start_record", async (ctx) => {
|
|
|
76907
77805
|
* @param ids 直播间ID列表
|
|
76908
77806
|
* @returns 批量操作结果
|
|
76909
77807
|
*/
|
|
76910
|
-
router$
|
|
77808
|
+
router$a.post("/manager/batch_stop_record", async (ctx) => {
|
|
76911
77809
|
const { ids } = ctx.request.body;
|
|
76912
77810
|
ctx.body = { payload: await recorderService.batchStopRecord(ids) };
|
|
76913
77811
|
});
|
|
@@ -76917,7 +77815,7 @@ router$9.post("/manager/batch_stop_record", async (ctx) => {
|
|
|
76917
77815
|
* @param url 直播间地址
|
|
76918
77816
|
* @returns 直播间信息
|
|
76919
77817
|
*/
|
|
76920
|
-
router$
|
|
77818
|
+
router$a.get("/manager/resolveChannel", async (ctx) => {
|
|
76921
77819
|
const { url } = ctx.query;
|
|
76922
77820
|
const data = await recorderService.resolveChannel(url);
|
|
76923
77821
|
ctx.body = { payload: data };
|
|
@@ -76928,7 +77826,7 @@ router$9.get("/manager/resolveChannel", async (ctx) => {
|
|
|
76928
77826
|
* @param url 直播间地址
|
|
76929
77827
|
* @returns 直播间信息
|
|
76930
77828
|
*/
|
|
76931
|
-
router$
|
|
77829
|
+
router$a.get("/manager/resolve", async (ctx) => {
|
|
76932
77830
|
const { url } = ctx.query;
|
|
76933
77831
|
const data = await recorderService.resolve(url);
|
|
76934
77832
|
ctx.body = { payload: data };
|
|
@@ -76939,7 +77837,7 @@ router$9.get("/manager/resolve", async (ctx) => {
|
|
|
76939
77837
|
* @param channelURLs 直播间地址数组
|
|
76940
77838
|
* @returns 批量解析结果
|
|
76941
77839
|
*/
|
|
76942
|
-
router$
|
|
77840
|
+
router$a.post("/manager/batchResolveChannel", async (ctx) => {
|
|
76943
77841
|
const { channelURLs } = ctx.request.body;
|
|
76944
77842
|
const data = await recorderService.batchResolveChannel(channelURLs);
|
|
76945
77843
|
ctx.body = { payload: data };
|
|
@@ -76951,7 +77849,7 @@ router$9.post("/manager/batchResolveChannel", async (ctx) => {
|
|
|
76951
77849
|
* @param forceRequest 强制查询直播间信息,不受配置限制,默认true
|
|
76952
77850
|
* @returns 直播间实时信息列表
|
|
76953
77851
|
*/
|
|
76954
|
-
router$
|
|
77852
|
+
router$a.post("/manager/liveInfo", async (ctx) => {
|
|
76955
77853
|
const { ids } = ctx.request.body;
|
|
76956
77854
|
const forceRequest = ctx.request.body.forceRequest ?? true;
|
|
76957
77855
|
let requestInfoForRecord = true;
|
|
@@ -76966,12 +77864,93 @@ router$9.post("/manager/liveInfo", async (ctx) => {
|
|
|
76966
77864
|
payload: list,
|
|
76967
77865
|
};
|
|
76968
77866
|
});
|
|
77867
|
+
router$a.get("/douyin/live-info", async (ctx) => {
|
|
77868
|
+
const { roomId, platform, dev } = ctx.request.query;
|
|
77869
|
+
if (platform !== "douyin") {
|
|
77870
|
+
ctx.body = { error: "Platform not supported" };
|
|
77871
|
+
ctx.status = 400;
|
|
77872
|
+
return;
|
|
77873
|
+
}
|
|
77874
|
+
try {
|
|
77875
|
+
const info = await index.getInfo(roomId, { api: "balance" });
|
|
77876
|
+
const body = {
|
|
77877
|
+
title: info.title,
|
|
77878
|
+
owner: info.owner,
|
|
77879
|
+
living: info.living,
|
|
77880
|
+
};
|
|
77881
|
+
if (dev) {
|
|
77882
|
+
body["dev"] = info;
|
|
77883
|
+
}
|
|
77884
|
+
ctx.body = body;
|
|
77885
|
+
}
|
|
77886
|
+
catch (error) {
|
|
77887
|
+
ctx.status = 500;
|
|
77888
|
+
ctx.body = { error: error.message };
|
|
77889
|
+
}
|
|
77890
|
+
});
|
|
77891
|
+
/**
|
|
77892
|
+
* 获取抖音直播间流信息,for bgo
|
|
77893
|
+
* @route GET /recorder/douyin/stream-info
|
|
77894
|
+
* @param roomId 直播间ID
|
|
77895
|
+
* @param platform 直播平台,必须为douyin
|
|
77896
|
+
* @param quality 画质,原画(origin)、蓝光(uhd)、超清(hd)、高清(sd)、标清(ld),音频流(ao),真原画(real_origin),默认为origin
|
|
77897
|
+
* @param dev 是否返回开发信息,默认为false
|
|
77898
|
+
* @returns 直播流信息
|
|
77899
|
+
*/
|
|
77900
|
+
router$a.get("/douyin/stream-info", async (ctx) => {
|
|
77901
|
+
const { roomId, platform, dev, quality } = ctx.request.query;
|
|
77902
|
+
if (platform !== "douyin") {
|
|
77903
|
+
ctx.body = { error: "Platform not supported" };
|
|
77904
|
+
ctx.status = 400;
|
|
77905
|
+
return;
|
|
77906
|
+
}
|
|
77907
|
+
try {
|
|
77908
|
+
const info = await index.getStream({
|
|
77909
|
+
channelId: roomId,
|
|
77910
|
+
quality: getSingleQueryValue(quality) || "origin",
|
|
77911
|
+
streamPriorities: [],
|
|
77912
|
+
sourcePriorities: [],
|
|
77913
|
+
formatPriorities: ["flv"],
|
|
77914
|
+
});
|
|
77915
|
+
const body = { stream: info.currentStream.url };
|
|
77916
|
+
if (dev) {
|
|
77917
|
+
body["dev"] = info;
|
|
77918
|
+
}
|
|
77919
|
+
ctx.body = body;
|
|
77920
|
+
}
|
|
77921
|
+
catch (error) {
|
|
77922
|
+
ctx.status = 500;
|
|
77923
|
+
ctx.body = { error: error.message };
|
|
77924
|
+
}
|
|
77925
|
+
});
|
|
77926
|
+
function handleRecorderUpgrade(request, socket, head) {
|
|
77927
|
+
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
77928
|
+
index.logObj.info("[danma-test-ws] upgrade request", {
|
|
77929
|
+
path: url.pathname,
|
|
77930
|
+
search: url.search,
|
|
77931
|
+
remoteAddress: request.socket.remoteAddress,
|
|
77932
|
+
remotePort: request.socket.remotePort,
|
|
77933
|
+
});
|
|
77934
|
+
if (url.pathname !== DANMA_TEST_WS_PATH) {
|
|
77935
|
+
return false;
|
|
77936
|
+
}
|
|
77937
|
+
if (url.searchParams.get("mode") === "reject-upgrade") {
|
|
77938
|
+
index.logObj.info("[danma-test-ws] reject upgrade", { path: url.pathname, search: url.search });
|
|
77939
|
+
socket.write("HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n");
|
|
77940
|
+
socket.destroy();
|
|
77941
|
+
return true;
|
|
77942
|
+
}
|
|
77943
|
+
danmaTestWSS.handleUpgrade(request, socket, head, (ws) => {
|
|
77944
|
+
danmaTestWSS.emit("connection", ws, request);
|
|
77945
|
+
});
|
|
77946
|
+
return true;
|
|
77947
|
+
}
|
|
76969
77948
|
|
|
76970
|
-
const router$
|
|
77949
|
+
const router$9 = new Router$1({
|
|
76971
77950
|
prefix: "/bili",
|
|
76972
77951
|
});
|
|
76973
77952
|
// 验证视频上传参数
|
|
76974
|
-
router$
|
|
77953
|
+
router$9.post("/validUploadParams", async (ctx) => {
|
|
76975
77954
|
const params = ctx.request.body;
|
|
76976
77955
|
// @ts-ignore
|
|
76977
77956
|
const [status, msg] = await index.validateBiliupConfig(params);
|
|
@@ -76985,7 +77964,7 @@ router$8.post("/validUploadParams", async (ctx) => {
|
|
|
76985
77964
|
/**
|
|
76986
77965
|
* 投稿中心视频列表
|
|
76987
77966
|
*/
|
|
76988
|
-
router$
|
|
77967
|
+
router$9.get("/archives", async (ctx) => {
|
|
76989
77968
|
const params = ctx.request.query;
|
|
76990
77969
|
const { uid } = params;
|
|
76991
77970
|
const data = await index.biliApi.getArchives(params, uid);
|
|
@@ -76994,53 +77973,43 @@ router$8.get("/archives", async (ctx) => {
|
|
|
76994
77973
|
/**
|
|
76995
77974
|
* 用户视频详情
|
|
76996
77975
|
*/
|
|
76997
|
-
router$
|
|
77976
|
+
router$9.get("/user/archive/:bvid", async (ctx) => {
|
|
76998
77977
|
const params = ctx.request.query;
|
|
76999
77978
|
const { uid } = params;
|
|
77000
77979
|
const { bvid } = ctx.params;
|
|
77001
77980
|
const data = await index.biliApi.getArchiveDetail(bvid, uid);
|
|
77002
77981
|
ctx.body = data;
|
|
77003
77982
|
});
|
|
77004
|
-
router$
|
|
77983
|
+
router$9.post("/checkTag", async (ctx) => {
|
|
77005
77984
|
const { tag, uid, } = ctx.request.body;
|
|
77006
77985
|
const data = await index.biliApi.checkTag(tag, uid);
|
|
77007
77986
|
ctx.body = data;
|
|
77008
77987
|
});
|
|
77009
|
-
router$
|
|
77988
|
+
router$9.get("/searchTopic", async (ctx) => {
|
|
77010
77989
|
const { keyword, uid } = ctx.request.query;
|
|
77011
77990
|
const data = await index.biliApi.searchTopic(keyword, uid);
|
|
77012
77991
|
ctx.body = data;
|
|
77013
77992
|
});
|
|
77014
|
-
router$
|
|
77993
|
+
router$9.get("/seasons", async (ctx) => {
|
|
77015
77994
|
const { uid } = ctx.request.query;
|
|
77016
77995
|
const data = await index.biliApi.getSeasonList(uid);
|
|
77017
77996
|
ctx.body = data;
|
|
77018
77997
|
});
|
|
77019
|
-
router$
|
|
77998
|
+
router$9.get("/season/:aid", async (ctx) => {
|
|
77020
77999
|
const { uid } = ctx.request.query;
|
|
77021
78000
|
const { aid } = ctx.params;
|
|
77022
78001
|
const data = await index.biliApi.getSessionId(Number(aid), uid);
|
|
77023
78002
|
ctx.body = data;
|
|
77024
78003
|
});
|
|
77025
|
-
router$
|
|
78004
|
+
router$9.get("/platformArchiveDetail", async (ctx) => {
|
|
77026
78005
|
const { aid, uid } = ctx.request.query;
|
|
77027
78006
|
const data = await index.biliApi.getPlatformArchiveDetail(aid, uid);
|
|
77028
78007
|
ctx.body = data;
|
|
77029
78008
|
});
|
|
77030
|
-
router$8.get("/platformPre", async (ctx) => {
|
|
77031
|
-
const { uid } = ctx.request.query;
|
|
77032
|
-
const data = await index.biliApi.getPlatformPre(uid);
|
|
77033
|
-
ctx.body = data;
|
|
77034
|
-
});
|
|
77035
|
-
router$8.get("/typeDesc", async (ctx) => {
|
|
77036
|
-
const { tid, uid } = ctx.request.query;
|
|
77037
|
-
const data = await index.biliApi.getTypeDesc(tid, uid);
|
|
77038
|
-
ctx.body = data;
|
|
77039
|
-
});
|
|
77040
78009
|
/**
|
|
77041
78010
|
* 上传以及续传视频
|
|
77042
78011
|
*/
|
|
77043
|
-
router$
|
|
78012
|
+
router$9.post("/upload", async (ctx) => {
|
|
77044
78013
|
const data = ctx.request.body;
|
|
77045
78014
|
if (!data.uid) {
|
|
77046
78015
|
ctx.body = "uid required";
|
|
@@ -77080,7 +78049,7 @@ router$8.post("/upload", async (ctx) => {
|
|
|
77080
78049
|
});
|
|
77081
78050
|
// 登录相关
|
|
77082
78051
|
const loginObj = {};
|
|
77083
|
-
router$
|
|
78052
|
+
router$9.post("/login", async (ctx) => {
|
|
77084
78053
|
const tv = new index.TvQrcodeLogin();
|
|
77085
78054
|
const id = index.uuid();
|
|
77086
78055
|
loginObj[id] = {
|
|
@@ -77112,7 +78081,7 @@ router$8.post("/login", async (ctx) => {
|
|
|
77112
78081
|
id,
|
|
77113
78082
|
};
|
|
77114
78083
|
});
|
|
77115
|
-
router$
|
|
78084
|
+
router$9.post("/login/cancel", async (ctx) => {
|
|
77116
78085
|
const { id } = ctx.request.body;
|
|
77117
78086
|
if (!id) {
|
|
77118
78087
|
ctx.body = "id required";
|
|
@@ -77129,7 +78098,7 @@ router$8.post("/login/cancel", async (ctx) => {
|
|
|
77129
78098
|
tv.interrupt();
|
|
77130
78099
|
ctx.body = "success";
|
|
77131
78100
|
});
|
|
77132
|
-
router$
|
|
78101
|
+
router$9.get("/login/poll", async (ctx) => {
|
|
77133
78102
|
const { id } = ctx.request.query;
|
|
77134
78103
|
if (!id) {
|
|
77135
78104
|
ctx.body = "id required";
|
|
@@ -77144,13 +78113,13 @@ router$8.get("/login/poll", async (ctx) => {
|
|
|
77144
78113
|
}
|
|
77145
78114
|
ctx.body = index.omit(loginInfo, ["client"]);
|
|
77146
78115
|
});
|
|
77147
|
-
router$
|
|
78116
|
+
router$9.post("/formatTitle", async (ctx) => {
|
|
77148
78117
|
const data = ctx.request.body;
|
|
77149
78118
|
const template = (data.template || "");
|
|
77150
78119
|
const title = index.formatTitle(data.options, template);
|
|
77151
78120
|
ctx.body = title;
|
|
77152
78121
|
});
|
|
77153
|
-
router$
|
|
78122
|
+
router$9.post("/formatPartTitle", async (ctx) => {
|
|
77154
78123
|
const data = ctx.request.body;
|
|
77155
78124
|
const template = (data.template || "");
|
|
77156
78125
|
const title = index.formatPartTitle(data.options ?? {
|
|
@@ -77163,7 +78132,7 @@ router$8.post("/formatPartTitle", async (ctx) => {
|
|
|
77163
78132
|
}, template);
|
|
77164
78133
|
ctx.body = title;
|
|
77165
78134
|
});
|
|
77166
|
-
router$
|
|
78135
|
+
router$9.post("/formatDesc", async (ctx) => {
|
|
77167
78136
|
const data = ctx.request.body;
|
|
77168
78137
|
const template = (data.template || "");
|
|
77169
78138
|
const desc = index.formatDesc(data.options ?? {
|
|
@@ -77212,7 +78181,7 @@ async function flvRepair(input, output, opts) {
|
|
|
77212
78181
|
index.taskQueue.addTask(task, true);
|
|
77213
78182
|
return task;
|
|
77214
78183
|
}
|
|
77215
|
-
class MesioCommand extends EventEmitter$
|
|
78184
|
+
class MesioCommand extends EventEmitter$4 {
|
|
77216
78185
|
_input = "";
|
|
77217
78186
|
_output = "";
|
|
77218
78187
|
_inputOptions = [];
|
|
@@ -77290,7 +78259,7 @@ class MesioCommand extends EventEmitter$3 {
|
|
|
77290
78259
|
}
|
|
77291
78260
|
}
|
|
77292
78261
|
}
|
|
77293
|
-
class BililiveRecorderCommand extends EventEmitter$
|
|
78262
|
+
class BililiveRecorderCommand extends EventEmitter$4 {
|
|
77294
78263
|
_input = "";
|
|
77295
78264
|
_output = "";
|
|
77296
78265
|
_inputOptions = [];
|
|
@@ -77434,10 +78403,10 @@ const generateWaveformData = async (videoFilePath) => {
|
|
|
77434
78403
|
}
|
|
77435
78404
|
};
|
|
77436
78405
|
|
|
77437
|
-
const router$
|
|
78406
|
+
const router$8 = new Router$1({
|
|
77438
78407
|
prefix: "/task",
|
|
77439
78408
|
});
|
|
77440
|
-
router$
|
|
78409
|
+
router$8.get("/", async (ctx) => {
|
|
77441
78410
|
const type = ctx.query.type;
|
|
77442
78411
|
let data = index.handleListTask();
|
|
77443
78412
|
if (type) {
|
|
@@ -77448,42 +78417,42 @@ router$7.get("/", async (ctx) => {
|
|
|
77448
78417
|
runningTaskNum: data.filter((item) => item.status === "running").length,
|
|
77449
78418
|
};
|
|
77450
78419
|
});
|
|
77451
|
-
router$
|
|
78420
|
+
router$8.get("/:id", async (ctx) => {
|
|
77452
78421
|
const { id } = ctx.params;
|
|
77453
78422
|
ctx.body = index.handleQueryTask(id);
|
|
77454
78423
|
});
|
|
77455
|
-
router$
|
|
78424
|
+
router$8.post("/:id/pause", async (ctx) => {
|
|
77456
78425
|
const { id } = ctx.params;
|
|
77457
78426
|
console.log(id);
|
|
77458
78427
|
index.handlePauseTask(id);
|
|
77459
78428
|
ctx.body = { code: 0 };
|
|
77460
78429
|
});
|
|
77461
|
-
router$
|
|
78430
|
+
router$8.post("/:id/resume", async (ctx) => {
|
|
77462
78431
|
const { id } = ctx.params;
|
|
77463
78432
|
index.handleResumeTask(id);
|
|
77464
78433
|
ctx.body = { code: 0 };
|
|
77465
78434
|
});
|
|
77466
|
-
router$
|
|
78435
|
+
router$8.post("/:id/kill", async (ctx) => {
|
|
77467
78436
|
const { id } = ctx.params;
|
|
77468
78437
|
index.handleKillTask(id);
|
|
77469
78438
|
ctx.body = { code: 0 };
|
|
77470
78439
|
});
|
|
77471
|
-
router$
|
|
78440
|
+
router$8.post("/:id/interrupt", async (ctx) => {
|
|
77472
78441
|
const { id } = ctx.params;
|
|
77473
78442
|
index.hanldeInterruptTask(id);
|
|
77474
78443
|
ctx.body = { code: 0 };
|
|
77475
78444
|
});
|
|
77476
|
-
router$
|
|
78445
|
+
router$8.post("/:id/removeRecord", async (ctx) => {
|
|
77477
78446
|
const { id } = ctx.params;
|
|
77478
78447
|
index.handleRemoveTask(id);
|
|
77479
78448
|
ctx.body = { code: 0 };
|
|
77480
78449
|
});
|
|
77481
|
-
router$
|
|
78450
|
+
router$8.post("/:id/restart", async (ctx) => {
|
|
77482
78451
|
const { id } = ctx.params;
|
|
77483
78452
|
index.handleRestartTask(id);
|
|
77484
78453
|
ctx.body = { code: 0 };
|
|
77485
78454
|
});
|
|
77486
|
-
router$
|
|
78455
|
+
router$8.post("/:id/removeFile", async (ctx) => {
|
|
77487
78456
|
const { id } = ctx.params;
|
|
77488
78457
|
const task = index.taskQueue.queryTask(id);
|
|
77489
78458
|
if (!task) {
|
|
@@ -77501,17 +78470,17 @@ router$7.post("/:id/removeFile", async (ctx) => {
|
|
|
77501
78470
|
await index.trashItem(task.output);
|
|
77502
78471
|
ctx.body = { code: 0 };
|
|
77503
78472
|
});
|
|
77504
|
-
router$
|
|
78473
|
+
router$8.post("/:id/start", async (ctx) => {
|
|
77505
78474
|
const { id } = ctx.params;
|
|
77506
78475
|
index.handleStartTask(id);
|
|
77507
78476
|
ctx.body = { code: 0 };
|
|
77508
78477
|
});
|
|
77509
|
-
router$
|
|
78478
|
+
router$8.post("/removeBatch", async (ctx) => {
|
|
77510
78479
|
const { ids } = ctx.request.body;
|
|
77511
78480
|
ids.forEach((id) => index.handleRemoveTask(id));
|
|
77512
78481
|
ctx.body = { code: 0 };
|
|
77513
78482
|
});
|
|
77514
|
-
router$
|
|
78483
|
+
router$8.post("/videoMeta", async (ctx) => {
|
|
77515
78484
|
const { file } = ctx.request.body;
|
|
77516
78485
|
console.log(ctx.params);
|
|
77517
78486
|
if (!file) {
|
|
@@ -77522,7 +78491,7 @@ router$7.post("/videoMeta", async (ctx) => {
|
|
|
77522
78491
|
const data = await index.readVideoMeta(file, {});
|
|
77523
78492
|
ctx.body = data;
|
|
77524
78493
|
});
|
|
77525
|
-
router$
|
|
78494
|
+
router$8.post("/convertXml2Ass", async (ctx) => {
|
|
77526
78495
|
const { input, output, preset, options } = ctx.request.body;
|
|
77527
78496
|
if (!input || !output) {
|
|
77528
78497
|
ctx.status = 400;
|
|
@@ -77556,12 +78525,12 @@ router$7.post("/convertXml2Ass", async (ctx) => {
|
|
|
77556
78525
|
ctx.body = { taskId: task.taskId, output: task.output };
|
|
77557
78526
|
}
|
|
77558
78527
|
});
|
|
77559
|
-
router$
|
|
78528
|
+
router$8.post("/checkMergeVideos", async (ctx) => {
|
|
77560
78529
|
const { inputVideos } = ctx.request.body;
|
|
77561
78530
|
const result = await index.checkMergeVideos(inputVideos);
|
|
77562
78531
|
ctx.body = result;
|
|
77563
78532
|
});
|
|
77564
|
-
router$
|
|
78533
|
+
router$8.post("/mergeVideo", async (ctx) => {
|
|
77565
78534
|
const { inputVideos, options } = ctx.request.body;
|
|
77566
78535
|
if (!inputVideos || inputVideos.length < 2) {
|
|
77567
78536
|
ctx.status = 400;
|
|
@@ -77579,7 +78548,7 @@ router$7.post("/mergeVideo", async (ctx) => {
|
|
|
77579
78548
|
});
|
|
77580
78549
|
ctx.body = { taskId: task.taskId };
|
|
77581
78550
|
});
|
|
77582
|
-
router$
|
|
78551
|
+
router$8.post("/transcode", async (ctx) => {
|
|
77583
78552
|
const { input, outputName, ffmpegOptions, options } = ctx.request.body;
|
|
77584
78553
|
if (!input) {
|
|
77585
78554
|
ctx.status = 400;
|
|
@@ -77597,7 +78566,7 @@ router$7.post("/transcode", async (ctx) => {
|
|
|
77597
78566
|
/**
|
|
77598
78567
|
* 烧录
|
|
77599
78568
|
*/
|
|
77600
|
-
router$
|
|
78569
|
+
router$8.post("/burn", async (ctx) => {
|
|
77601
78570
|
const { files, output, options } = ctx.request.body;
|
|
77602
78571
|
if (options?.uploadOptions?.upload && !options?.uploadOptions?.aid) {
|
|
77603
78572
|
const [status, msg] = index.validateBiliupConfig(options?.uploadOptions?.config || {});
|
|
@@ -77626,7 +78595,7 @@ router$7.post("/burn", async (ctx) => {
|
|
|
77626
78595
|
/**
|
|
77627
78596
|
* flv修复
|
|
77628
78597
|
*/
|
|
77629
|
-
router$
|
|
78598
|
+
router$8.post("/flvRepair", async (ctx) => {
|
|
77630
78599
|
const { input, output, options } = ctx.request.body;
|
|
77631
78600
|
const task = await flvRepair(input, output, options);
|
|
77632
78601
|
ctx.body = { taskId: task.taskId };
|
|
@@ -77634,7 +78603,7 @@ router$7.post("/flvRepair", async (ctx) => {
|
|
|
77634
78603
|
/**
|
|
77635
78604
|
* 切片
|
|
77636
78605
|
*/
|
|
77637
|
-
router$
|
|
78606
|
+
router$8.post("/cut", async (ctx) => {
|
|
77638
78607
|
const { files, output, options, ffmpegOptions } = ctx.request.body;
|
|
77639
78608
|
// 处理srt字幕切割
|
|
77640
78609
|
const srtContent = files.srtContent;
|
|
@@ -77679,7 +78648,7 @@ router$7.post("/cut", async (ctx) => {
|
|
|
77679
78648
|
* 字幕分割
|
|
77680
78649
|
* 输入:srt字幕内容
|
|
77681
78650
|
*/
|
|
77682
|
-
router$
|
|
78651
|
+
router$8.post("/cutSubtitle", async (ctx) => {
|
|
77683
78652
|
const data = ctx.request.body;
|
|
77684
78653
|
const nodeList = parseSync(data.srtContent);
|
|
77685
78654
|
// console.log("解析后的节点数量:", nodeList.length, nodeList);
|
|
@@ -77718,22 +78687,22 @@ router$7.post("/cutSubtitle", async (ctx) => {
|
|
|
77718
78687
|
}
|
|
77719
78688
|
ctx.body = "success";
|
|
77720
78689
|
});
|
|
77721
|
-
router$
|
|
78690
|
+
router$8.post("/addExtraVideoTask", async (ctx) => {
|
|
77722
78691
|
const { taskId, filePath, partName } = ctx.request.body;
|
|
77723
78692
|
index.biliApi.addExtraVideoTask(taskId, filePath, partName);
|
|
77724
78693
|
ctx.body = { code: 0 };
|
|
77725
78694
|
});
|
|
77726
|
-
router$
|
|
78695
|
+
router$8.post("/editVideoPartName", async (ctx) => {
|
|
77727
78696
|
const { taskId, partName } = ctx.request.body;
|
|
77728
78697
|
index.biliApi.editVideoPartName(taskId, partName);
|
|
77729
78698
|
ctx.body = { code: 0 };
|
|
77730
78699
|
});
|
|
77731
|
-
router$
|
|
78700
|
+
router$8.post("/queryVideoStatus", async (ctx) => {
|
|
77732
78701
|
const { taskId } = ctx.request.body;
|
|
77733
78702
|
const res = await index.biliApi.queryVideoStatus(taskId);
|
|
77734
78703
|
ctx.body = res;
|
|
77735
78704
|
});
|
|
77736
|
-
router$
|
|
78705
|
+
router$8.get("/:id/download", async (ctx) => {
|
|
77737
78706
|
const { id } = ctx.params;
|
|
77738
78707
|
const task = index.taskQueue.queryTask(id);
|
|
77739
78708
|
if (!task) {
|
|
@@ -77754,7 +78723,7 @@ router$7.get("/:id/download", async (ctx) => {
|
|
|
77754
78723
|
const fileId = fileCache.setFile(task.output);
|
|
77755
78724
|
ctx.body = fileId;
|
|
77756
78725
|
});
|
|
77757
|
-
router$
|
|
78726
|
+
router$8.post("/testVirtualRecord", async (ctx) => {
|
|
77758
78727
|
const { config, folderPath, startTime } = ctx.request.body;
|
|
77759
78728
|
if (!config) {
|
|
77760
78729
|
ctx.status = 400;
|
|
@@ -77795,7 +78764,7 @@ router$7.post("/testVirtualRecord", async (ctx) => {
|
|
|
77795
78764
|
ctx.body = error instanceof Error ? error.message : "Internal server error";
|
|
77796
78765
|
}
|
|
77797
78766
|
});
|
|
77798
|
-
router$
|
|
78767
|
+
router$8.post("/executeVirtualRecord", async (ctx) => {
|
|
77799
78768
|
const { config, folderPath, startTime } = ctx.request.body;
|
|
77800
78769
|
if (!config) {
|
|
77801
78770
|
ctx.status = 400;
|
|
@@ -77839,7 +78808,7 @@ router$7.post("/executeVirtualRecord", async (ctx) => {
|
|
|
77839
78808
|
/**
|
|
77840
78809
|
* 生成waveform数据
|
|
77841
78810
|
*/
|
|
77842
|
-
router$
|
|
78811
|
+
router$8.post("/extractPeaks", async (ctx) => {
|
|
77843
78812
|
const { input } = ctx.request.body;
|
|
77844
78813
|
if (!input) {
|
|
77845
78814
|
ctx.status = 400;
|
|
@@ -77857,7 +78826,7 @@ router$7.post("/extractPeaks", async (ctx) => {
|
|
|
77857
78826
|
/**
|
|
77858
78827
|
* 分析波形数据,主要用于检测唱歌边界点
|
|
77859
78828
|
*/
|
|
77860
|
-
router$
|
|
78829
|
+
router$8.post("/analyzerWaveform", async (ctx) => {
|
|
77861
78830
|
const { input, config } = ctx.request.body;
|
|
77862
78831
|
if (!input) {
|
|
77863
78832
|
ctx.status = 400;
|
|
@@ -77868,10 +78837,10 @@ router$7.post("/analyzerWaveform", async (ctx) => {
|
|
|
77868
78837
|
ctx.body = { output: data };
|
|
77869
78838
|
});
|
|
77870
78839
|
|
|
77871
|
-
const router$
|
|
78840
|
+
const router$7 = new Router$1({
|
|
77872
78841
|
prefix: "/assets",
|
|
77873
78842
|
});
|
|
77874
|
-
router$
|
|
78843
|
+
router$7.get("/cover/:filename", async (ctx) => {
|
|
77875
78844
|
const { filename } = ctx.params;
|
|
77876
78845
|
const coverPath = path$7.join(exports.config.userDataPath, "cover", filename);
|
|
77877
78846
|
if (await index.fs.pathExists(coverPath)) {
|
|
@@ -77883,7 +78852,7 @@ router$6.get("/cover/:filename", async (ctx) => {
|
|
|
77883
78852
|
ctx.body = "Cover not found";
|
|
77884
78853
|
}
|
|
77885
78854
|
});
|
|
77886
|
-
router$
|
|
78855
|
+
router$7.get("/download/:id", async (ctx) => {
|
|
77887
78856
|
const { id } = ctx.params;
|
|
77888
78857
|
const file = fileCache.get(id);
|
|
77889
78858
|
if (!file) {
|
|
@@ -77907,8 +78876,8 @@ async function download$1(output, url, options) {
|
|
|
77907
78876
|
const mp4Output = index.replaceExtName(output, ".mp4");
|
|
77908
78877
|
if ((await index.fs.pathExists(mp4Output)) && !options.override)
|
|
77909
78878
|
throw new Error(`${mp4Output}已存在`);
|
|
77910
|
-
const { dir, name } = require$$0$
|
|
77911
|
-
const tsOutput = require$$0$
|
|
78879
|
+
const { dir, name } = require$$0$7.parse(output);
|
|
78880
|
+
const tsOutput = require$$0$7.join(dir, `${name}.ts`);
|
|
77912
78881
|
if (await index.fs.pathExists(tsOutput)) {
|
|
77913
78882
|
throw new Error(`${tsOutput}已存在,您可以直接执行转封装命令,或者删除后重新下载`);
|
|
77914
78883
|
}
|
|
@@ -77916,10 +78885,10 @@ async function download$1(output, url, options) {
|
|
|
77916
78885
|
const downloader = new index.M3U8Downloader(url, tsOutput, {
|
|
77917
78886
|
convert2Mp4: false,
|
|
77918
78887
|
ffmpegPath: ffmpegPath,
|
|
77919
|
-
segmentsDir: require$$0$
|
|
78888
|
+
segmentsDir: require$$0$7.join(index.getTempPath(), index.uuid()),
|
|
77920
78889
|
});
|
|
77921
78890
|
const task = new index.KuaishouDownloadVideoTask(downloader, {
|
|
77922
|
-
name: `下载任务:${require$$0$
|
|
78891
|
+
name: `下载任务:${require$$0$7.parse(output).name}`,
|
|
77923
78892
|
}, {
|
|
77924
78893
|
onEnd: async () => {
|
|
77925
78894
|
const outputName = `${name}.mp4`;
|
|
@@ -77962,7 +78931,7 @@ var kuaishou = {
|
|
|
77962
78931
|
var dist = {};
|
|
77963
78932
|
|
|
77964
78933
|
(function (exports) {
|
|
77965
|
-
Object.defineProperty(exports,'__esModule',{value:!0}),exports.DownloaderHelper=exports.DH_STATES=void 0;var _typeof='function'==typeof Symbol&&'symbol'==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&'function'==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?'symbol':typeof a},_createClass=function(){function a(a,b){for(var c,d=0;d<b.length;d++)c=b[d],c.enumerable=c.enumerable||!1,c.configurable=!0,'value'in c&&(c.writable=!0),Object.defineProperty(a,c.key,c);}return function(b,c,d){return c&&a(b.prototype,c),d&&a(b,d),b}}(),_fs=require$$0$8,fs=_interopRequireWildcard(_fs),_url=require$$0$a,_path=require$$0$6,path=_interopRequireWildcard(_path),_http=require$$3$1,http=_interopRequireWildcard(_http),_https=require$$1$7,https=_interopRequireWildcard(_https),_events=require$$0$7;function _interopRequireWildcard(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b.default=a,b}function _classCallCheck(a,b){if(!(a instanceof b))throw new TypeError('Cannot call a class as a function')}function _possibleConstructorReturn(a,b){if(!a)throw new ReferenceError('this hasn\'t been initialised - super() hasn\'t been called');return b&&('object'==typeof b||'function'==typeof b)?b:a}function _inherits(a,b){if('function'!=typeof b&&null!==b)throw new TypeError('Super expression must either be null or a function, not '+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b);}var DH_STATES=exports.DH_STATES={IDLE:'IDLE',SKIPPED:'SKIPPED',STARTED:'STARTED',DOWNLOADING:'DOWNLOADING',RETRY:'RETRY',PAUSED:'PAUSED',RESUMED:'RESUMED',STOPPED:'STOPPED',FINISHED:'FINISHED',FAILED:'FAILED'};exports.DownloaderHelper=function(a){function b(a,c){var d=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};_classCallCheck(this,b);var e=_possibleConstructorReturn(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,{captureRejections:!0}));return e.__validate(a,c)?(e.url=e.requestURL=a.trim(),e.state=DH_STATES.IDLE,e.__defaultOpts={body:null,retry:!1,method:'GET',headers:{},fileName:'',timeout:-1,metadata:null,override:!1,forceResume:!1,removeOnStop:!0,removeOnFail:!0,progressThrottle:1e3,httpRequestOptions:{},httpsRequestOptions:{},resumeOnIncomplete:!0,resumeIfFileExists:!1,resumeOnIncompleteMaxRetry:5},e.__opts=Object.assign({},e.__defaultOpts),e.__pipes=[],e.__total=0,e.__downloaded=0,e.__progress=0,e.__retryCount=0,e.__retryTimeout=null,e.__resumeRetryCount=0,e.__states=DH_STATES,e.__promise=null,e.__request=null,e.__response=null,e.__isAborted=!1,e.__isResumed=!1,e.__isResumable=!1,e.__isRedirected=!1,e.__destFolder=c,e.__statsEstimate={time:0,bytes:0,prevBytes:0,throttleTime:0},e.__fileName='',e.__filePath='',e.updateOptions(d),e):_possibleConstructorReturn(e)}return _inherits(b,a),_createClass(b,[{key:'start',value:function c(){var a=this,b=function(){return new Promise(function(b,c){a.__promise={resolve:b,reject:c},a.__start();})};return this.__opts.resumeIfFileExists&&this.state!==this.__states.RESUMED?this.getTotalSize().then(function(c){var d=c.name,e=c.total,f=a.__opts.override;if(a.__opts.override=!0,a.__filePath=a.__getFilePath(d),a.__opts.override=f,a.__filePath&&fs.existsSync(a.__filePath)){var g=a.__getFilesizeInBytes(a.__filePath);return g===e?b():a.resumeFromFile(a.__filePath,{total:e,fileName:d})}return b()}):b()}},{key:'pause',value:function b(){var a=this;return this.state===this.__states.STOPPED?Promise.resolve(!0):(this.__response&&(this.__response.unpipe(),this.__pipes.forEach(function(a){return a.stream.unpipe()})),this.__fileStream&&this.__fileStream.removeAllListeners(),this.__requestAbort(),this.__closeFileStream().then(function(){return a.__setState(a.__states.PAUSED),a.emit('pause'),!0}))}},{key:'resume',value:function a(){return this.__promise?this.state===this.__states.STOPPED?Promise.resolve(!1):(this.__setState(this.__states.RESUMED),this.__isResumable&&(this.__isResumed=!0,this.__reqOptions.headers.range='bytes='+this.__downloaded+'-'),this.emit('resume',this.__isResumed),this.__start()):this.start()}},{key:'stop',value:function c(){var a=this;if(this.state===this.__states.STOPPED)return Promise.resolve(!0);var b=function(){return new Promise(function(b,c){fs.access(a.__filePath,function(d){return d?(a.__emitStop(),b(!0)):void fs.unlink(a.__filePath,function(d){return d?(a.__setState(a.__states.FAILED),a.emit('error',d),c(d)):void(a.__emitStop(),b(!0))})});})};return this.__requestAbort(),this.__closeFileStream().then(function(){return a.__opts.removeOnStop?b():(a.__emitStop(),Promise.resolve(!0))})}},{key:'pipe',value:function c(a){var b=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null;return this.__pipes.push({stream:a,options:b}),a}},{key:'unpipe',value:function d(){var a=this,b=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,c=function(b){return a.__response?a.__response.unpipe(b):b.unpipe()};if(b){var e=this.__pipes.find(function(a){return a.stream===b});return void(e&&(c(b),this.__pipes=this.__pipes.filter(function(a){return a.stream!==b})))}this.__pipes.forEach(function(a){return c(a.stream)}),this.__pipes=[];}},{key:'getDownloadPath',value:function a(){return this.__filePath}},{key:'isResumable',value:function a(){return this.__isResumable}},{key:'updateOptions',value:function c(a){var b=1<arguments.length&&void 0!==arguments[1]?arguments[1]:'';this.__opts=Object.assign({},this.__opts,a),this.__headers=this.__opts.headers,-1<this.__opts.timeout&&(this.__opts.httpRequestOptions.timeout=this.__opts.timeout,this.__opts.httpsRequestOptions.timeout=this.__opts.timeout),('number'!=typeof this.__opts.progressThrottle||0>this.__opts.progressThrottle)&&(this.__opts.progressThrottle=this.__defaultOpts.progressThrottle),this.url=b||this.url,this.__reqOptions=this.__getReqOptions(this.__opts.method,this.url,this.__opts.headers),this.__initProtocol(this.url);}},{key:'getOptions',value:function a(){return this.__opts}},{key:'getMetadata',value:function a(){return this.__opts.metadata}},{key:'getStats',value:function a(){return {total:this.__total,name:this.__fileName,downloaded:this.__downloaded,progress:this.__progress,speed:this.__statsEstimate.bytes}}},{key:'getTotalSize',value:function b(){var a=this;return new Promise(function(b,c){var d=function(b){a.__initProtocol(b);var c=Object.assign({},a.__headers);c.hasOwnProperty('range')&&delete c.range;var d=a.__getReqOptions('HEAD',b,c);return Object.assign({},a.__reqOptions,d)},e=0,f=null,g=function(b,c){if(!a.__opts.retry||'object'!==_typeof(a.__opts.retry))return Promise.reject(b||new Error('wrong retry options'));f&&(clearTimeout(f),f=null);var g=a.__opts.retry,i=g.delay,j=void 0===i?0:i,k=g.maxRetries,l=void 0===k?999:k;return e>=l?Promise.reject(b||new Error('reached the maximum retries')):(e++,a.__setState(a.__states.RETRY),a.emit('retry',e,a.__opts.retry,b),new Promise(function(b){f=setTimeout(function(){a.__setState(a.__states.IDLE),h(c,d(c)),b();},j);}))},h=function(e,i){f&&(clearTimeout(f),f=null);var j=a.__protocol.request(i,function(f){if(a.__isRequireRedirect(f)){var i=/^https?:\/\//.test(f.headers.location)?f.headers.location:new _url.URL(f.headers.location,e).href;return a.emit('redirected',i,e),h(i,d(i))}if(200>f.statusCode||400<=f.statusCode){var j=new Error('Response status was '+f.statusCode);return a.__opts.retry&&500<=f.statusCode&&600>f.statusCode?g(j,e).catch(c):c(j)}b({name:a.__getFileNameFromHeaders(f.headers,f),total:parseInt(f.headers['content-length'])||null});});j.on('error',function(b){return a.__opts.retry?g(b,e).catch(c):void c(b)}),j.on('timeout',function(){return a.__opts.retry?g(new Error('timeout'),e).catch(c):void c(new Error('timeout'))}),j.on('uncaughtException',function(b){return a.__opts.retry?g(b,e).catch(c):void c(b)}),j.end();};h(a.url,d(a.url));})}},{key:'getResumeState',value:function a(){return {downloaded:this.__downloaded,filePath:this.__filePath,fileName:this.__fileName,total:this.__total}}},{key:'resumeFromFile',value:function d(a){var b=this,c=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return this.__opts.override=!0,this.__filePath=a,(c.total&&c.fileName?Promise.resolve({name:c.fileName,total:c.total}):this.getTotalSize()).then(function(a){var d=a.name,e=a.total;return b.__total=c.total||e,b.__fileName=c.fileName||d,b.__downloaded=c.downloaded||b.__getFilesizeInBytes(b.__filePath),b.__reqOptions.headers.range='bytes='+b.__downloaded+'-',b.__isResumed=!0,b.__isResumable=!0,b.__setState(b.__states.RESUMED),b.emit('resume',b.__isResumed),new Promise(function(a,c){b.__promise={resolve:a,reject:c},b.__start();})})}},{key:'__start',value:function a(){this.__isRedirected||this.state===this.__states.RESUMED||(this.emit('start'),this.__setState(this.__states.STARTED),this.__initProtocol(this.url)),this.__response=null,this.__isAborted=!1,this.__request&&!this.__request.destroyed&&this.__request.destroy(),this.__retryTimeout&&(clearTimeout(this.__retryTimeout),this.__retryTimeout=null),this.__request=this.__downloadRequest(this.__promise.resolve,this.__promise.reject),this.__request.on('error',this.__onError(this.__promise.resolve,this.__promise.reject)),this.__request.on('timeout',this.__onTimeout(this.__promise.resolve,this.__promise.reject)),this.__request.on('uncaughtException',this.__onError(this.__promise.resolve,this.__promise.reject,!0)),this.__opts.body&&this.__request.write(this.__opts.body),this.__request.end();}},{key:'__resolvePending',value:function b(){if(this.__promise){var a=this.__promise.resolve;return this.__promise=null,a(!0)}}},{key:'__downloadRequest',value:function d(a,b){var c=this;return this.__protocol.request(this.__reqOptions,function(d){if(c.__response=d,c.__isResumed||(c.__total=parseInt(d.headers['content-length'])||null,c.__resetStats()),c.__isRequireRedirect(d)){var e=/^https?:\/\//.test(d.headers.location)?d.headers.location:new _url.URL(d.headers.location,c.url).href;return c.__isRedirected=!0,c.__initProtocol(e),c.emit('redirected',e,c.url),c.__start()}if(200>d.statusCode||400<=d.statusCode){var f=new Error('Response status was '+d.statusCode);return (f.status=d.statusCode||0,f.body=d.body||'',500<=d.statusCode&&600>d.statusCode)?c.__onError(a,b)(f):(c.__setState(c.__states.FAILED),c.emit('error',f),b(f))}c.__opts.forceResume?c.__isResumable=!0:d.headers.hasOwnProperty('accept-ranges')&&'none'!==d.headers['accept-ranges']&&(c.__isResumable=!0),c.__startDownload(d,a,b);})}},{key:'__startDownload',value:function h(a,b,c){var d=this,e=a;if(!this.__isResumed){var i=this.__getFileNameFromHeaders(a.headers);if(this.__filePath=this.__getFilePath(i),this.__fileName=this.__filePath.split(path.sep).pop(),fs.existsSync(this.__filePath)){var f=this.__getFilesizeInBytes(this.__filePath),g=this.__total?this.__total:0;if('object'===_typeof(this.__opts.override)&&this.__opts.override.skip&&(this.__opts.override.skipSmaller||f>=g))return this.emit('skip',{totalSize:this.__total,fileName:this.__fileName,filePath:this.__filePath,downloadedSize:f}),this.__setState(this.__states.SKIPPED),b(!0)}this.__fileStream=fs.createWriteStream(this.__filePath,{});}else this.__fileStream=fs.createWriteStream(this.__filePath,{flags:'a'});this.emit('download',{fileName:this.__fileName,filePath:this.__filePath,totalSize:this.__total,isResumed:this.__isResumed,downloadedSize:this.__downloaded}),this.__retryCount=0,this.__isResumed=!1,this.__isRedirected=!1,this.__setState(this.__states.DOWNLOADING),this.__statsEstimate.time=new Date,this.__statsEstimate.throttleTime=new Date,e.on('data',function(a){return d.__calculateStats(a.length)}),this.__pipes.forEach(function(a){e.pipe(a.stream,a.options),e=a.stream;}),e.pipe(this.__fileStream),e.on('error',this.__onError(b,c)),this.__fileStream.on('finish',this.__onFinished(b,c)),this.__fileStream.on('error',this.__onError(b,c));}},{key:'__hasFinished',value:function a(){return !this.__isAborted&&-1===[this.__states.PAUSED,this.__states.STOPPED,this.__states.RETRY,this.__states.FAILED,this.__states.RESUMED].indexOf(this.state)}},{key:'__isRequireRedirect',value:function b(a){return 300<a.statusCode&&400>a.statusCode&&a.headers.hasOwnProperty('location')&&a.headers.location}},{key:'__onFinished',value:function d(a,b){var c=this;return function(){c.__fileStream.close(function(d){if(d)return b(d);if(c.__hasFinished()){var e=!!c.__total&&c.__downloaded!==c.__total;if(e&&c.__isResumable&&c.__opts.resumeOnIncomplete&&c.__resumeRetryCount<=c.__opts.resumeOnIncompleteMaxRetry)return c.__resumeRetryCount++,c.emit('warning',new Error('uncomplete download, retrying')),c.resume();c.__setState(c.__states.FINISHED),c.__pipes=[],c.emit('end',{fileName:c.__fileName,filePath:c.__filePath,totalSize:c.__total,incomplete:e,onDiskSize:c.__getFilesizeInBytes(c.__filePath),downloadedSize:c.__downloaded});}return a(c.__downloaded===c.__total)});}}},{key:'__closeFileStream',value:function b(){var a=this;return this.__fileStream?new Promise(function(b,c){a.__fileStream.close(function(a){return a?c(a):b(!0)});}):Promise.resolve(!0)}},{key:'__onError',value:function e(a,b){var c=this,d=!!(2<arguments.length&&void 0!==arguments[2])&&arguments[2];return function(a){return c.__pipes=[],d&&c.__requestAbort(),c.state===c.__states.STOPPED||c.state===c.__states.FAILED?void 0:c.__opts.retry?c.__retry(a).catch(function(d){c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),c.emit('error',d?d:a),b(d?d:a);});}):c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),c.emit('error',a),b(a);})}}},{key:'__retry',value:function h(){var a=this,b=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null;if(!this.__opts.retry||'object'!==_typeof(this.__opts.retry))return Promise.reject(b||new Error('wrong retry options'));var c=this.__opts.retry,d=c.delay,e=void 0===d?0:d,f=c.maxRetries,g=void 0===f?999:f;return this.__retryCount>=g?Promise.reject(b||new Error('reached the maximum retries')):(this.__retryCount++,this.__setState(this.__states.RETRY),this.emit('retry',this.__retryCount,this.__opts.retry,b),this.__response&&(this.__response.unpipe(),this.__pipes.forEach(function(a){return a.stream.unpipe()})),this.__fileStream&&this.__fileStream.removeAllListeners(),this.__requestAbort(),this.__closeFileStream().then(function(){return new Promise(function(b){return a.__retryTimeout=setTimeout(function(){return b(0<a.__downloaded?a.resume():a.__start())},e)})}))}},{key:'__onTimeout',value:function d(a,b){var c=this;return function(){return c.__requestAbort(),c.__opts.retry?c.__retry(new Error('timeout')).catch(function(a){c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),a?b(a):(c.emit('timeout'),b(new Error('timeout')));});}):c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),c.emit('timeout'),b(new Error('timeout'));})}}},{key:'__resetStats',value:function a(){this.__retryCount=0,this.__downloaded=0,this.__progress=0,this.__resumeRetryCount=0,this.__statsEstimate={time:0,bytes:0,prevBytes:0,throttleTime:0};}},{key:'__getFileNameFromHeaders',value:function k(a,b){var c='',d=/.*filename\*=.*?'.*?'([^"].+?[^"])(?:(?:;)|$)/i,e=/.*filename="(.*?)";?/i,f=/.*filename=([^"].+?[^"])(?:(?:;)|$)/i,g=a.hasOwnProperty('content-disposition'),h=g?a['content-disposition'].match(d):null,i=!g||h?null:a['content-disposition'].match(e),j=!g||h||i?null:a['content-disposition'].match(f);return g&&(h||i||j)?(c=a['content-disposition'],c=c.trim(),h?c=h[1]:i?c=i[1]:j&&(c=j[1]),c=c.replace(/[/\\]/g,'')):0<path.basename(new _url.URL(this.requestURL).pathname).length?c=path.basename(new _url.URL(this.requestURL).pathname):c=new _url.URL(this.requestURL).hostname+'.html',this.__opts.fileName?this.__getFileNameFromOpts(c,b):c.replace(/\.*$/,'')}},{key:'__getFilePath',value:function d(a){var b=path.join(this.__destFolder,a),c=b;return this.__opts.override||this.state===this.__states.RESUMED||(c=this.__uniqFileNameSync(c),b!==c&&this.emit('renamed',{path:c,fileName:c.split(path.sep).pop(),prevPath:b,prevFileName:b.split(path.sep).pop()})),c}},{key:'__getFileNameFromOpts',value:function g(a,b){if(!this.__opts.fileName)return a;if('string'==typeof this.__opts.fileName)return this.__opts.fileName;if('function'==typeof this.__opts.fileName){var h=path.join(this.__destFolder,a);return b&&b.headers||this.__response&&this.__response.headers?this.__opts.fileName(a,h,(b?b:this.__response).headers['content-type']):this.__opts.fileName(a,h)}if('object'===_typeof(this.__opts.fileName)){var c=this.__opts.fileName,d=c.name,e=!!c.hasOwnProperty('ext')&&c.ext;if('string'==typeof e)return d+'.'+e;if('boolean'==typeof e){if(e)return d;var f=a.includes('.')?a.split('.').pop():'';return ''===f?d:d+'.'+f}}return a}},{key:'__calculateStats',value:function f(a){var b=new Date,c=b-this.__statsEstimate.time,d=b-this.__statsEstimate.throttleTime,e=this.__total||0;a&&(this.__downloaded+=a,this.__progress=0===e?0:100*(this.__downloaded/e),(this.__downloaded===e||1e3<c)&&(this.__statsEstimate.time=b,this.__statsEstimate.bytes=this.__downloaded-this.__statsEstimate.prevBytes,this.__statsEstimate.prevBytes=this.__downloaded),(this.__downloaded===e||d>this.__opts.progressThrottle)&&(this.__statsEstimate.throttleTime=b,this.emit('progress.throttled',this.getStats())),this.emit('progress',this.getStats()));}},{key:'__setState',value:function b(a){this.state=a,this.emit('stateChanged',this.state);}},{key:'__getReqOptions',value:function f(a,b){var c=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},d=new _url.URL(b),e={protocol:d.protocol,host:d.hostname,port:d.port,path:d.pathname+d.search,method:a};return c&&(e.headers=c),e}},{key:'__getFilesizeInBytes',value:function d(a){try{var b=fs.statSync(a,{throwIfNoEntry:!1}),c=b.size||0;return c}catch(a){this.emit('warning',a);}return 0}},{key:'__validate',value:function d(a,b){if('string'!=typeof a)throw new Error('URL should be an string');if(''===a.trim())throw new Error('URL couldn\'t be empty');if('string'!=typeof b)throw new Error('Destination Folder should be an string');if(''===b.trim())throw new Error('Destination Folder couldn\'t be empty');if(!fs.existsSync(b))throw new Error('Destination Folder must exist');var c=fs.statSync(b);if(!c.isDirectory())throw new Error('Destination Folder must be a directory');try{fs.accessSync(b,fs.constants.W_OK);}catch(a){throw new Error('Destination Folder must be writable')}return !0}},{key:'__initProtocol',value:function c(a){var b=this.__getReqOptions(this.__opts.method,a,this.__headers);this.requestURL=a,-1<a.indexOf('https://')?(this.__protocol=https,b.agent=new https.Agent({keepAlive:!1}),this.__reqOptions=Object.assign({},b,this.__opts.httpsRequestOptions)):(this.__protocol=http,b.agent=new http.Agent({keepAlive:!1}),this.__reqOptions=Object.assign({},b,this.__opts.httpRequestOptions));}},{key:'__uniqFileNameSync',value:function f(a){if('string'!=typeof a||''===a)return a;try{fs.accessSync(a,fs.F_OK);var b=a.match(/(.*)(\([0-9]+\))(\..*)$/),c=b?b[1].trim():a,d=b?parseInt(b[2].replace(/\(|\)/,'')):0,e=a.split('.').pop();return e!==a&&0<e.length?(e='.'+e,c=c.replace(e,'')):e='',this.__uniqFileNameSync(c+' ('+ ++d+')'+e)}catch(b){return a}}},{key:'__removeFile',value:function b(){var a=this;return new Promise(function(b){return a.__fileStream?void a.__fileStream.close(function(c){return c&&a.emit('warning',c),a.__opts.removeOnFail?fs.access(a.__filePath,function(d){return d?b():void fs.unlink(a.__filePath,function(d){d&&a.emit('warning',c),b();})}):void b()}):b()})}},{key:'__requestAbort',value:function a(){this.__isAborted=!0,this.__retryTimeout&&(clearTimeout(this.__retryTimeout),this.__retryTimeout=null),this.__response&&this.__response.destroy(),this.__request&&(this.__request.destroy?this.__request.destroy():this.__request.abort());}},{key:'__emitStop',value:function a(){this.__resolvePending(),this.__setState(this.__states.STOPPED),this.emit('stop');}}]),b}(_events.EventEmitter);
|
|
78934
|
+
Object.defineProperty(exports,'__esModule',{value:!0}),exports.DownloaderHelper=exports.DH_STATES=void 0;var _typeof='function'==typeof Symbol&&'symbol'==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&'function'==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?'symbol':typeof a},_createClass=function(){function a(a,b){for(var c,d=0;d<b.length;d++)c=b[d],c.enumerable=c.enumerable||!1,c.configurable=!0,'value'in c&&(c.writable=!0),Object.defineProperty(a,c.key,c);}return function(b,c,d){return c&&a(b.prototype,c),d&&a(b,d),b}}(),_fs=require$$0$8,fs=_interopRequireWildcard(_fs),_url=require$$0$a,_path=require$$0$7,path=_interopRequireWildcard(_path),_http=require$$3$1,http=_interopRequireWildcard(_http),_https=require$$1$7,https=_interopRequireWildcard(_https),_events=require$$0$4;function _interopRequireWildcard(a){if(a&&a.__esModule)return a;var b={};if(null!=a)for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b.default=a,b}function _classCallCheck(a,b){if(!(a instanceof b))throw new TypeError('Cannot call a class as a function')}function _possibleConstructorReturn(a,b){if(!a)throw new ReferenceError('this hasn\'t been initialised - super() hasn\'t been called');return b&&('object'==typeof b||'function'==typeof b)?b:a}function _inherits(a,b){if('function'!=typeof b&&null!==b)throw new TypeError('Super expression must either be null or a function, not '+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b);}var DH_STATES=exports.DH_STATES={IDLE:'IDLE',SKIPPED:'SKIPPED',STARTED:'STARTED',DOWNLOADING:'DOWNLOADING',RETRY:'RETRY',PAUSED:'PAUSED',RESUMED:'RESUMED',STOPPED:'STOPPED',FINISHED:'FINISHED',FAILED:'FAILED'};exports.DownloaderHelper=function(a){function b(a,c){var d=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};_classCallCheck(this,b);var e=_possibleConstructorReturn(this,(b.__proto__||Object.getPrototypeOf(b)).call(this,{captureRejections:!0}));return e.__validate(a,c)?(e.url=e.requestURL=a.trim(),e.state=DH_STATES.IDLE,e.__defaultOpts={body:null,retry:!1,method:'GET',headers:{},fileName:'',timeout:-1,metadata:null,override:!1,forceResume:!1,removeOnStop:!0,removeOnFail:!0,progressThrottle:1e3,httpRequestOptions:{},httpsRequestOptions:{},resumeOnIncomplete:!0,resumeIfFileExists:!1,resumeOnIncompleteMaxRetry:5},e.__opts=Object.assign({},e.__defaultOpts),e.__pipes=[],e.__total=0,e.__downloaded=0,e.__progress=0,e.__retryCount=0,e.__retryTimeout=null,e.__resumeRetryCount=0,e.__states=DH_STATES,e.__promise=null,e.__request=null,e.__response=null,e.__isAborted=!1,e.__isResumed=!1,e.__isResumable=!1,e.__isRedirected=!1,e.__destFolder=c,e.__statsEstimate={time:0,bytes:0,prevBytes:0,throttleTime:0},e.__fileName='',e.__filePath='',e.updateOptions(d),e):_possibleConstructorReturn(e)}return _inherits(b,a),_createClass(b,[{key:'start',value:function c(){var a=this,b=function(){return new Promise(function(b,c){a.__promise={resolve:b,reject:c},a.__start();})};return this.__opts.resumeIfFileExists&&this.state!==this.__states.RESUMED?this.getTotalSize().then(function(c){var d=c.name,e=c.total,f=a.__opts.override;if(a.__opts.override=!0,a.__filePath=a.__getFilePath(d),a.__opts.override=f,a.__filePath&&fs.existsSync(a.__filePath)){var g=a.__getFilesizeInBytes(a.__filePath);return g===e?b():a.resumeFromFile(a.__filePath,{total:e,fileName:d})}return b()}):b()}},{key:'pause',value:function b(){var a=this;return this.state===this.__states.STOPPED?Promise.resolve(!0):(this.__response&&(this.__response.unpipe(),this.__pipes.forEach(function(a){return a.stream.unpipe()})),this.__fileStream&&this.__fileStream.removeAllListeners(),this.__requestAbort(),this.__closeFileStream().then(function(){return a.__setState(a.__states.PAUSED),a.emit('pause'),!0}))}},{key:'resume',value:function a(){return this.__promise?this.state===this.__states.STOPPED?Promise.resolve(!1):(this.__setState(this.__states.RESUMED),this.__isResumable&&(this.__isResumed=!0,this.__reqOptions.headers.range='bytes='+this.__downloaded+'-'),this.emit('resume',this.__isResumed),this.__start()):this.start()}},{key:'stop',value:function c(){var a=this;if(this.state===this.__states.STOPPED)return Promise.resolve(!0);var b=function(){return new Promise(function(b,c){fs.access(a.__filePath,function(d){return d?(a.__emitStop(),b(!0)):void fs.unlink(a.__filePath,function(d){return d?(a.__setState(a.__states.FAILED),a.emit('error',d),c(d)):void(a.__emitStop(),b(!0))})});})};return this.__requestAbort(),this.__closeFileStream().then(function(){return a.__opts.removeOnStop?b():(a.__emitStop(),Promise.resolve(!0))})}},{key:'pipe',value:function c(a){var b=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null;return this.__pipes.push({stream:a,options:b}),a}},{key:'unpipe',value:function d(){var a=this,b=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,c=function(b){return a.__response?a.__response.unpipe(b):b.unpipe()};if(b){var e=this.__pipes.find(function(a){return a.stream===b});return void(e&&(c(b),this.__pipes=this.__pipes.filter(function(a){return a.stream!==b})))}this.__pipes.forEach(function(a){return c(a.stream)}),this.__pipes=[];}},{key:'getDownloadPath',value:function a(){return this.__filePath}},{key:'isResumable',value:function a(){return this.__isResumable}},{key:'updateOptions',value:function c(a){var b=1<arguments.length&&void 0!==arguments[1]?arguments[1]:'';this.__opts=Object.assign({},this.__opts,a),this.__headers=this.__opts.headers,-1<this.__opts.timeout&&(this.__opts.httpRequestOptions.timeout=this.__opts.timeout,this.__opts.httpsRequestOptions.timeout=this.__opts.timeout),('number'!=typeof this.__opts.progressThrottle||0>this.__opts.progressThrottle)&&(this.__opts.progressThrottle=this.__defaultOpts.progressThrottle),this.url=b||this.url,this.__reqOptions=this.__getReqOptions(this.__opts.method,this.url,this.__opts.headers),this.__initProtocol(this.url);}},{key:'getOptions',value:function a(){return this.__opts}},{key:'getMetadata',value:function a(){return this.__opts.metadata}},{key:'getStats',value:function a(){return {total:this.__total,name:this.__fileName,downloaded:this.__downloaded,progress:this.__progress,speed:this.__statsEstimate.bytes}}},{key:'getTotalSize',value:function b(){var a=this;return new Promise(function(b,c){var d=function(b){a.__initProtocol(b);var c=Object.assign({},a.__headers);c.hasOwnProperty('range')&&delete c.range;var d=a.__getReqOptions('HEAD',b,c);return Object.assign({},a.__reqOptions,d)},e=0,f=null,g=function(b,c){if(!a.__opts.retry||'object'!==_typeof(a.__opts.retry))return Promise.reject(b||new Error('wrong retry options'));f&&(clearTimeout(f),f=null);var g=a.__opts.retry,i=g.delay,j=void 0===i?0:i,k=g.maxRetries,l=void 0===k?999:k;return e>=l?Promise.reject(b||new Error('reached the maximum retries')):(e++,a.__setState(a.__states.RETRY),a.emit('retry',e,a.__opts.retry,b),new Promise(function(b){f=setTimeout(function(){a.__setState(a.__states.IDLE),h(c,d(c)),b();},j);}))},h=function(e,i){f&&(clearTimeout(f),f=null);var j=a.__protocol.request(i,function(f){if(a.__isRequireRedirect(f)){var i=/^https?:\/\//.test(f.headers.location)?f.headers.location:new _url.URL(f.headers.location,e).href;return a.emit('redirected',i,e),h(i,d(i))}if(200>f.statusCode||400<=f.statusCode){var j=new Error('Response status was '+f.statusCode);return a.__opts.retry&&500<=f.statusCode&&600>f.statusCode?g(j,e).catch(c):c(j)}b({name:a.__getFileNameFromHeaders(f.headers,f),total:parseInt(f.headers['content-length'])||null});});j.on('error',function(b){return a.__opts.retry?g(b,e).catch(c):void c(b)}),j.on('timeout',function(){return a.__opts.retry?g(new Error('timeout'),e).catch(c):void c(new Error('timeout'))}),j.on('uncaughtException',function(b){return a.__opts.retry?g(b,e).catch(c):void c(b)}),j.end();};h(a.url,d(a.url));})}},{key:'getResumeState',value:function a(){return {downloaded:this.__downloaded,filePath:this.__filePath,fileName:this.__fileName,total:this.__total}}},{key:'resumeFromFile',value:function d(a){var b=this,c=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};return this.__opts.override=!0,this.__filePath=a,(c.total&&c.fileName?Promise.resolve({name:c.fileName,total:c.total}):this.getTotalSize()).then(function(a){var d=a.name,e=a.total;return b.__total=c.total||e,b.__fileName=c.fileName||d,b.__downloaded=c.downloaded||b.__getFilesizeInBytes(b.__filePath),b.__reqOptions.headers.range='bytes='+b.__downloaded+'-',b.__isResumed=!0,b.__isResumable=!0,b.__setState(b.__states.RESUMED),b.emit('resume',b.__isResumed),new Promise(function(a,c){b.__promise={resolve:a,reject:c},b.__start();})})}},{key:'__start',value:function a(){this.__isRedirected||this.state===this.__states.RESUMED||(this.emit('start'),this.__setState(this.__states.STARTED),this.__initProtocol(this.url)),this.__response=null,this.__isAborted=!1,this.__request&&!this.__request.destroyed&&this.__request.destroy(),this.__retryTimeout&&(clearTimeout(this.__retryTimeout),this.__retryTimeout=null),this.__request=this.__downloadRequest(this.__promise.resolve,this.__promise.reject),this.__request.on('error',this.__onError(this.__promise.resolve,this.__promise.reject)),this.__request.on('timeout',this.__onTimeout(this.__promise.resolve,this.__promise.reject)),this.__request.on('uncaughtException',this.__onError(this.__promise.resolve,this.__promise.reject,!0)),this.__opts.body&&this.__request.write(this.__opts.body),this.__request.end();}},{key:'__resolvePending',value:function b(){if(this.__promise){var a=this.__promise.resolve;return this.__promise=null,a(!0)}}},{key:'__downloadRequest',value:function d(a,b){var c=this;return this.__protocol.request(this.__reqOptions,function(d){if(c.__response=d,c.__isResumed||(c.__total=parseInt(d.headers['content-length'])||null,c.__resetStats()),c.__isRequireRedirect(d)){var e=/^https?:\/\//.test(d.headers.location)?d.headers.location:new _url.URL(d.headers.location,c.url).href;return c.__isRedirected=!0,c.__initProtocol(e),c.emit('redirected',e,c.url),c.__start()}if(200>d.statusCode||400<=d.statusCode){var f=new Error('Response status was '+d.statusCode);return (f.status=d.statusCode||0,f.body=d.body||'',500<=d.statusCode&&600>d.statusCode)?c.__onError(a,b)(f):(c.__setState(c.__states.FAILED),c.emit('error',f),b(f))}c.__opts.forceResume?c.__isResumable=!0:d.headers.hasOwnProperty('accept-ranges')&&'none'!==d.headers['accept-ranges']&&(c.__isResumable=!0),c.__startDownload(d,a,b);})}},{key:'__startDownload',value:function h(a,b,c){var d=this,e=a;if(!this.__isResumed){var i=this.__getFileNameFromHeaders(a.headers);if(this.__filePath=this.__getFilePath(i),this.__fileName=this.__filePath.split(path.sep).pop(),fs.existsSync(this.__filePath)){var f=this.__getFilesizeInBytes(this.__filePath),g=this.__total?this.__total:0;if('object'===_typeof(this.__opts.override)&&this.__opts.override.skip&&(this.__opts.override.skipSmaller||f>=g))return this.emit('skip',{totalSize:this.__total,fileName:this.__fileName,filePath:this.__filePath,downloadedSize:f}),this.__setState(this.__states.SKIPPED),b(!0)}this.__fileStream=fs.createWriteStream(this.__filePath,{});}else this.__fileStream=fs.createWriteStream(this.__filePath,{flags:'a'});this.emit('download',{fileName:this.__fileName,filePath:this.__filePath,totalSize:this.__total,isResumed:this.__isResumed,downloadedSize:this.__downloaded}),this.__retryCount=0,this.__isResumed=!1,this.__isRedirected=!1,this.__setState(this.__states.DOWNLOADING),this.__statsEstimate.time=new Date,this.__statsEstimate.throttleTime=new Date,e.on('data',function(a){return d.__calculateStats(a.length)}),this.__pipes.forEach(function(a){e.pipe(a.stream,a.options),e=a.stream;}),e.pipe(this.__fileStream),e.on('error',this.__onError(b,c)),this.__fileStream.on('finish',this.__onFinished(b,c)),this.__fileStream.on('error',this.__onError(b,c));}},{key:'__hasFinished',value:function a(){return !this.__isAborted&&-1===[this.__states.PAUSED,this.__states.STOPPED,this.__states.RETRY,this.__states.FAILED,this.__states.RESUMED].indexOf(this.state)}},{key:'__isRequireRedirect',value:function b(a){return 300<a.statusCode&&400>a.statusCode&&a.headers.hasOwnProperty('location')&&a.headers.location}},{key:'__onFinished',value:function d(a,b){var c=this;return function(){c.__fileStream.close(function(d){if(d)return b(d);if(c.__hasFinished()){var e=!!c.__total&&c.__downloaded!==c.__total;if(e&&c.__isResumable&&c.__opts.resumeOnIncomplete&&c.__resumeRetryCount<=c.__opts.resumeOnIncompleteMaxRetry)return c.__resumeRetryCount++,c.emit('warning',new Error('uncomplete download, retrying')),c.resume();c.__setState(c.__states.FINISHED),c.__pipes=[],c.emit('end',{fileName:c.__fileName,filePath:c.__filePath,totalSize:c.__total,incomplete:e,onDiskSize:c.__getFilesizeInBytes(c.__filePath),downloadedSize:c.__downloaded});}return a(c.__downloaded===c.__total)});}}},{key:'__closeFileStream',value:function b(){var a=this;return this.__fileStream?new Promise(function(b,c){a.__fileStream.close(function(a){return a?c(a):b(!0)});}):Promise.resolve(!0)}},{key:'__onError',value:function e(a,b){var c=this,d=!!(2<arguments.length&&void 0!==arguments[2])&&arguments[2];return function(a){return c.__pipes=[],d&&c.__requestAbort(),c.state===c.__states.STOPPED||c.state===c.__states.FAILED?void 0:c.__opts.retry?c.__retry(a).catch(function(d){c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),c.emit('error',d?d:a),b(d?d:a);});}):c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),c.emit('error',a),b(a);})}}},{key:'__retry',value:function h(){var a=this,b=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null;if(!this.__opts.retry||'object'!==_typeof(this.__opts.retry))return Promise.reject(b||new Error('wrong retry options'));var c=this.__opts.retry,d=c.delay,e=void 0===d?0:d,f=c.maxRetries,g=void 0===f?999:f;return this.__retryCount>=g?Promise.reject(b||new Error('reached the maximum retries')):(this.__retryCount++,this.__setState(this.__states.RETRY),this.emit('retry',this.__retryCount,this.__opts.retry,b),this.__response&&(this.__response.unpipe(),this.__pipes.forEach(function(a){return a.stream.unpipe()})),this.__fileStream&&this.__fileStream.removeAllListeners(),this.__requestAbort(),this.__closeFileStream().then(function(){return new Promise(function(b){return a.__retryTimeout=setTimeout(function(){return b(0<a.__downloaded?a.resume():a.__start())},e)})}))}},{key:'__onTimeout',value:function d(a,b){var c=this;return function(){return c.__requestAbort(),c.__opts.retry?c.__retry(new Error('timeout')).catch(function(a){c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),a?b(a):(c.emit('timeout'),b(new Error('timeout')));});}):c.__removeFile().finally(function(){c.__setState(c.__states.FAILED),c.emit('timeout'),b(new Error('timeout'));})}}},{key:'__resetStats',value:function a(){this.__retryCount=0,this.__downloaded=0,this.__progress=0,this.__resumeRetryCount=0,this.__statsEstimate={time:0,bytes:0,prevBytes:0,throttleTime:0};}},{key:'__getFileNameFromHeaders',value:function k(a,b){var c='',d=/.*filename\*=.*?'.*?'([^"].+?[^"])(?:(?:;)|$)/i,e=/.*filename="(.*?)";?/i,f=/.*filename=([^"].+?[^"])(?:(?:;)|$)/i,g=a.hasOwnProperty('content-disposition'),h=g?a['content-disposition'].match(d):null,i=!g||h?null:a['content-disposition'].match(e),j=!g||h||i?null:a['content-disposition'].match(f);return g&&(h||i||j)?(c=a['content-disposition'],c=c.trim(),h?c=h[1]:i?c=i[1]:j&&(c=j[1]),c=c.replace(/[/\\]/g,'')):0<path.basename(new _url.URL(this.requestURL).pathname).length?c=path.basename(new _url.URL(this.requestURL).pathname):c=new _url.URL(this.requestURL).hostname+'.html',this.__opts.fileName?this.__getFileNameFromOpts(c,b):c.replace(/\.*$/,'')}},{key:'__getFilePath',value:function d(a){var b=path.join(this.__destFolder,a),c=b;return this.__opts.override||this.state===this.__states.RESUMED||(c=this.__uniqFileNameSync(c),b!==c&&this.emit('renamed',{path:c,fileName:c.split(path.sep).pop(),prevPath:b,prevFileName:b.split(path.sep).pop()})),c}},{key:'__getFileNameFromOpts',value:function g(a,b){if(!this.__opts.fileName)return a;if('string'==typeof this.__opts.fileName)return this.__opts.fileName;if('function'==typeof this.__opts.fileName){var h=path.join(this.__destFolder,a);return b&&b.headers||this.__response&&this.__response.headers?this.__opts.fileName(a,h,(b?b:this.__response).headers['content-type']):this.__opts.fileName(a,h)}if('object'===_typeof(this.__opts.fileName)){var c=this.__opts.fileName,d=c.name,e=!!c.hasOwnProperty('ext')&&c.ext;if('string'==typeof e)return d+'.'+e;if('boolean'==typeof e){if(e)return d;var f=a.includes('.')?a.split('.').pop():'';return ''===f?d:d+'.'+f}}return a}},{key:'__calculateStats',value:function f(a){var b=new Date,c=b-this.__statsEstimate.time,d=b-this.__statsEstimate.throttleTime,e=this.__total||0;a&&(this.__downloaded+=a,this.__progress=0===e?0:100*(this.__downloaded/e),(this.__downloaded===e||1e3<c)&&(this.__statsEstimate.time=b,this.__statsEstimate.bytes=this.__downloaded-this.__statsEstimate.prevBytes,this.__statsEstimate.prevBytes=this.__downloaded),(this.__downloaded===e||d>this.__opts.progressThrottle)&&(this.__statsEstimate.throttleTime=b,this.emit('progress.throttled',this.getStats())),this.emit('progress',this.getStats()));}},{key:'__setState',value:function b(a){this.state=a,this.emit('stateChanged',this.state);}},{key:'__getReqOptions',value:function f(a,b){var c=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},d=new _url.URL(b),e={protocol:d.protocol,host:d.hostname,port:d.port,path:d.pathname+d.search,method:a};return c&&(e.headers=c),e}},{key:'__getFilesizeInBytes',value:function d(a){try{var b=fs.statSync(a,{throwIfNoEntry:!1}),c=b.size||0;return c}catch(a){this.emit('warning',a);}return 0}},{key:'__validate',value:function d(a,b){if('string'!=typeof a)throw new Error('URL should be an string');if(''===a.trim())throw new Error('URL couldn\'t be empty');if('string'!=typeof b)throw new Error('Destination Folder should be an string');if(''===b.trim())throw new Error('Destination Folder couldn\'t be empty');if(!fs.existsSync(b))throw new Error('Destination Folder must exist');var c=fs.statSync(b);if(!c.isDirectory())throw new Error('Destination Folder must be a directory');try{fs.accessSync(b,fs.constants.W_OK);}catch(a){throw new Error('Destination Folder must be writable')}return !0}},{key:'__initProtocol',value:function c(a){var b=this.__getReqOptions(this.__opts.method,a,this.__headers);this.requestURL=a,-1<a.indexOf('https://')?(this.__protocol=https,b.agent=new https.Agent({keepAlive:!1}),this.__reqOptions=Object.assign({},b,this.__opts.httpsRequestOptions)):(this.__protocol=http,b.agent=new http.Agent({keepAlive:!1}),this.__reqOptions=Object.assign({},b,this.__opts.httpRequestOptions));}},{key:'__uniqFileNameSync',value:function f(a){if('string'!=typeof a||''===a)return a;try{fs.accessSync(a,fs.F_OK);var b=a.match(/(.*)(\([0-9]+\))(\..*)$/),c=b?b[1].trim():a,d=b?parseInt(b[2].replace(/\(|\)/,'')):0,e=a.split('.').pop();return e!==a&&0<e.length?(e='.'+e,c=c.replace(e,'')):e='',this.__uniqFileNameSync(c+' ('+ ++d+')'+e)}catch(b){return a}}},{key:'__removeFile',value:function b(){var a=this;return new Promise(function(b){return a.__fileStream?void a.__fileStream.close(function(c){return c&&a.emit('warning',c),a.__opts.removeOnFail?fs.access(a.__filePath,function(d){return d?b():void fs.unlink(a.__filePath,function(d){d&&a.emit('warning',c),b();})}):void b()}):b()})}},{key:'__requestAbort',value:function a(){this.__isAborted=!0,this.__retryTimeout&&(clearTimeout(this.__retryTimeout),this.__retryTimeout=null),this.__response&&this.__response.destroy(),this.__request&&(this.__request.destroy?this.__request.destroy():this.__request.abort());}},{key:'__emitStop',value:function a(){this.__resolvePending(),this.__setState(this.__states.STOPPED),this.emit('stop');}}]),b}(_events.EventEmitter);
|
|
77966
78935
|
} (dist));
|
|
77967
78936
|
|
|
77968
78937
|
async function download(output, url, options) {
|
|
@@ -78017,10 +78986,10 @@ var douyin = {
|
|
|
78017
78986
|
download,
|
|
78018
78987
|
};
|
|
78019
78988
|
|
|
78020
|
-
const router$
|
|
78989
|
+
const router$6 = new Router$1({
|
|
78021
78990
|
prefix: "/video",
|
|
78022
78991
|
});
|
|
78023
|
-
router$
|
|
78992
|
+
router$6.post("/parse", async (ctx) => {
|
|
78024
78993
|
let url = ctx.request.body.url;
|
|
78025
78994
|
if (!url) {
|
|
78026
78995
|
throw new Error("url is required");
|
|
@@ -78028,11 +78997,11 @@ router$5.post("/parse", async (ctx) => {
|
|
|
78028
78997
|
url = url.trim();
|
|
78029
78998
|
ctx.body = await parseVideo({ url });
|
|
78030
78999
|
});
|
|
78031
|
-
router$
|
|
79000
|
+
router$6.post("/download", async (ctx) => {
|
|
78032
79001
|
let options = ctx.request.body;
|
|
78033
79002
|
ctx.body = await downloadVideo(options);
|
|
78034
79003
|
});
|
|
78035
|
-
router$
|
|
79004
|
+
router$6.post("/sub/parse", async (ctx) => {
|
|
78036
79005
|
let data = ctx.request.body;
|
|
78037
79006
|
if (!data.url) {
|
|
78038
79007
|
throw new Error("url is required");
|
|
@@ -78040,12 +79009,12 @@ router$5.post("/sub/parse", async (ctx) => {
|
|
|
78040
79009
|
const res = await index.videoSub.parse(data.url);
|
|
78041
79010
|
ctx.body = res;
|
|
78042
79011
|
});
|
|
78043
|
-
router$
|
|
79012
|
+
router$6.post("/sub/add", async (ctx) => {
|
|
78044
79013
|
let data = ctx.request.body;
|
|
78045
79014
|
const res = index.videoSub.add(data);
|
|
78046
79015
|
ctx.body = res;
|
|
78047
79016
|
});
|
|
78048
|
-
router$
|
|
79017
|
+
router$6.post("/sub/remove", async (ctx) => {
|
|
78049
79018
|
let data = ctx.request.body;
|
|
78050
79019
|
if (!data.id) {
|
|
78051
79020
|
throw new Error("id is required");
|
|
@@ -78053,7 +79022,7 @@ router$5.post("/sub/remove", async (ctx) => {
|
|
|
78053
79022
|
const res = index.videoSub.remove(data.id);
|
|
78054
79023
|
ctx.body = res;
|
|
78055
79024
|
});
|
|
78056
|
-
router$
|
|
79025
|
+
router$6.post("/sub/update", async (ctx) => {
|
|
78057
79026
|
let data = ctx.request.body;
|
|
78058
79027
|
if (!data.id || !data.name || !data.platform || !data.subId) {
|
|
78059
79028
|
throw new Error("id, name, platform, subId is required");
|
|
@@ -78061,11 +79030,11 @@ router$5.post("/sub/update", async (ctx) => {
|
|
|
78061
79030
|
const res = index.videoSub.update(data);
|
|
78062
79031
|
ctx.body = res;
|
|
78063
79032
|
});
|
|
78064
|
-
router$
|
|
79033
|
+
router$6.get("/sub/list", async (ctx) => {
|
|
78065
79034
|
const res = index.videoSub.list();
|
|
78066
79035
|
ctx.body = res;
|
|
78067
79036
|
});
|
|
78068
|
-
router$
|
|
79037
|
+
router$6.post("/sub/check", async (ctx) => {
|
|
78069
79038
|
const data = ctx.request.body;
|
|
78070
79039
|
const res = await index.videoSub.check(data.id);
|
|
78071
79040
|
ctx.body = res;
|
|
@@ -78282,6 +79251,7 @@ async function downloadVideo(options) {
|
|
|
78282
79251
|
live_start_time: options?.extra?.live_start_time,
|
|
78283
79252
|
video_start_time: options?.extra?.video_start_time,
|
|
78284
79253
|
});
|
|
79254
|
+
return;
|
|
78285
79255
|
}
|
|
78286
79256
|
await index.douyu.download(filepath, options?.extra?.decodeData, {
|
|
78287
79257
|
danmu: options.danmu,
|
|
@@ -78388,22 +79358,34 @@ function extractBVNumber(videoUrl) {
|
|
|
78388
79358
|
}
|
|
78389
79359
|
}
|
|
78390
79360
|
|
|
78391
|
-
const router$
|
|
79361
|
+
const router$5 = new Router$1({
|
|
78392
79362
|
prefix: "/record-history",
|
|
78393
79363
|
});
|
|
79364
|
+
const resolveVideoFileExt = (videoFile) => {
|
|
79365
|
+
const extname = path$7.extname(videoFile).toLowerCase();
|
|
79366
|
+
switch (extname) {
|
|
79367
|
+
case ".flv":
|
|
79368
|
+
return "flv";
|
|
79369
|
+
case ".ts":
|
|
79370
|
+
return "ts";
|
|
79371
|
+
default:
|
|
79372
|
+
return "";
|
|
79373
|
+
}
|
|
79374
|
+
};
|
|
78394
79375
|
/**
|
|
78395
79376
|
* 查询直播记录
|
|
78396
79377
|
* @route GET /record-history/list
|
|
78397
79378
|
* @param {string} room_id - 房间号
|
|
78398
79379
|
* @param {string} platform - 平台
|
|
79380
|
+
* @param {string} [liveId] - 直播ID
|
|
78399
79381
|
* @param {number} [page=1] - 页码
|
|
78400
79382
|
* @param {number} [pageSize=100] - 每页条数
|
|
78401
79383
|
* @param {number} [startTime] - 开始时间(时间戳)
|
|
78402
79384
|
* @param {number} [endTime] - 结束时间(时间戳)
|
|
78403
79385
|
* @returns
|
|
78404
79386
|
*/
|
|
78405
|
-
router$
|
|
78406
|
-
const { room_id, platform, page, pageSize, startTime, endTime } = ctx.query;
|
|
79387
|
+
router$5.get("/list", async (ctx) => {
|
|
79388
|
+
const { room_id, platform, liveId, page, pageSize, startTime, endTime } = ctx.query;
|
|
78407
79389
|
if (!room_id || !platform) {
|
|
78408
79390
|
ctx.status = 400;
|
|
78409
79391
|
ctx.body = {
|
|
@@ -78416,6 +79398,7 @@ router$4.get("/list", async (ctx) => {
|
|
|
78416
79398
|
const result = index.recordHistory.queryRecordsByRoomAndPlatform({
|
|
78417
79399
|
room_id: room_id,
|
|
78418
79400
|
platform: platform,
|
|
79401
|
+
liveId: liveId ? String(liveId) : undefined,
|
|
78419
79402
|
page: page ? parseInt(page) : undefined,
|
|
78420
79403
|
pageSize: pageSize ? parseInt(pageSize) : undefined,
|
|
78421
79404
|
startTime: startTime ? parseInt(startTime) : undefined,
|
|
@@ -78448,7 +79431,7 @@ router$4.get("/list", async (ctx) => {
|
|
|
78448
79431
|
* @route DELETE /record-history/:id
|
|
78449
79432
|
* @param {number} id - 记录ID
|
|
78450
79433
|
*/
|
|
78451
|
-
router$
|
|
79434
|
+
router$5.delete("/:id", async (ctx) => {
|
|
78452
79435
|
const { id } = ctx.params;
|
|
78453
79436
|
if (!id || isNaN(parseInt(id))) {
|
|
78454
79437
|
ctx.status = 400;
|
|
@@ -78505,6 +79488,16 @@ const getVideoFile = async (id) => {
|
|
|
78505
79488
|
}
|
|
78506
79489
|
return null;
|
|
78507
79490
|
};
|
|
79491
|
+
const createVideoFileResponse = async (videoFile) => {
|
|
79492
|
+
const stats = await index.fs.stat(videoFile);
|
|
79493
|
+
return {
|
|
79494
|
+
videoFilePath: videoFile,
|
|
79495
|
+
videoFileId: fileCache.setFile(videoFile),
|
|
79496
|
+
videoFileExt: resolveVideoFileExt(videoFile),
|
|
79497
|
+
videoFileSize: stats.size,
|
|
79498
|
+
videoFileUpdatedAt: stats.mtimeMs,
|
|
79499
|
+
};
|
|
79500
|
+
};
|
|
78508
79501
|
/**
|
|
78509
79502
|
* 获取弹幕文件路径,优先查询ass文件,其次查询xml文件
|
|
78510
79503
|
* @param videoFile 视频文件路径
|
|
@@ -78521,12 +79514,24 @@ const getDanmaFile = async (videoFile) => {
|
|
|
78521
79514
|
}
|
|
78522
79515
|
return null;
|
|
78523
79516
|
};
|
|
79517
|
+
const createDanmaFileResponse = async (videoFile) => {
|
|
79518
|
+
const danmaFile = await getDanmaFile(videoFile);
|
|
79519
|
+
let danmaFileId = null;
|
|
79520
|
+
if (danmaFile) {
|
|
79521
|
+
danmaFileId = fileCache.setFile(danmaFile.file);
|
|
79522
|
+
}
|
|
79523
|
+
return {
|
|
79524
|
+
danmaFilePath: danmaFile?.file || null,
|
|
79525
|
+
danmaFileId,
|
|
79526
|
+
danmaFileExt: danmaFile?.ext || null,
|
|
79527
|
+
};
|
|
79528
|
+
};
|
|
78524
79529
|
/**
|
|
78525
|
-
*
|
|
79530
|
+
* 获取历史记录文件信息
|
|
78526
79531
|
* @route GET /record-history/file/:id
|
|
78527
79532
|
* @param {number} id - 记录ID
|
|
78528
79533
|
*/
|
|
78529
|
-
router$
|
|
79534
|
+
router$5.get("/file/:id", async (ctx) => {
|
|
78530
79535
|
const { id } = ctx.params;
|
|
78531
79536
|
if (!id || isNaN(parseInt(id))) {
|
|
78532
79537
|
ctx.status = 400;
|
|
@@ -78538,29 +79543,329 @@ router$4.get("/file/:id", async (ctx) => {
|
|
|
78538
79543
|
ctx.body = "视频文件不存在";
|
|
78539
79544
|
return;
|
|
78540
79545
|
}
|
|
78541
|
-
const
|
|
78542
|
-
const
|
|
78543
|
-
|
|
78544
|
-
|
|
78545
|
-
|
|
78546
|
-
|
|
78547
|
-
|
|
78548
|
-
|
|
78549
|
-
|
|
78550
|
-
|
|
79546
|
+
const videoInfo = await createVideoFileResponse(videoFile);
|
|
79547
|
+
const danmaInfo = await createDanmaFileResponse(videoFile);
|
|
79548
|
+
ctx.body = {
|
|
79549
|
+
...videoInfo,
|
|
79550
|
+
...danmaInfo,
|
|
79551
|
+
};
|
|
79552
|
+
});
|
|
79553
|
+
router$5.get("/recent-clips", async (ctx) => {
|
|
79554
|
+
const { room_id, platform, liveId } = ctx.query;
|
|
79555
|
+
if (!room_id || !platform) {
|
|
79556
|
+
ctx.status = 400;
|
|
79557
|
+
ctx.body = {
|
|
79558
|
+
code: 400,
|
|
79559
|
+
message: "房间号和平台不能为空",
|
|
79560
|
+
};
|
|
79561
|
+
return;
|
|
78551
79562
|
}
|
|
78552
|
-
|
|
78553
|
-
|
|
78554
|
-
|
|
78555
|
-
|
|
79563
|
+
try {
|
|
79564
|
+
const recentCandidates = index.recordHistory.queryRecentClipsByRoomAndPlatform({
|
|
79565
|
+
room_id: String(room_id),
|
|
79566
|
+
platform: String(platform),
|
|
79567
|
+
liveId: liveId ? String(liveId) : undefined,
|
|
79568
|
+
candidateLimit: 15,
|
|
79569
|
+
});
|
|
79570
|
+
const items = [];
|
|
79571
|
+
for (const clip of recentCandidates) {
|
|
79572
|
+
if (items.length >= 5)
|
|
79573
|
+
break;
|
|
79574
|
+
try {
|
|
79575
|
+
const videoFile = await getVideoFile(clip.id);
|
|
79576
|
+
if (!videoFile)
|
|
79577
|
+
continue;
|
|
79578
|
+
const videoInfo = await createVideoFileResponse(videoFile);
|
|
79579
|
+
items.push({
|
|
79580
|
+
id: clip.id,
|
|
79581
|
+
title: clip.title,
|
|
79582
|
+
liveStartTime: clip.live_start_time,
|
|
79583
|
+
recordStartTime: clip.record_start_time,
|
|
79584
|
+
recordEndTime: clip.record_end_time,
|
|
79585
|
+
videoDuration: clip.video_duration,
|
|
79586
|
+
...videoInfo,
|
|
79587
|
+
});
|
|
79588
|
+
}
|
|
79589
|
+
catch {
|
|
79590
|
+
continue;
|
|
79591
|
+
}
|
|
79592
|
+
}
|
|
79593
|
+
ctx.body = {
|
|
79594
|
+
code: 200,
|
|
79595
|
+
data: items,
|
|
79596
|
+
};
|
|
78556
79597
|
}
|
|
79598
|
+
catch (error) {
|
|
79599
|
+
ctx.status = 500;
|
|
79600
|
+
ctx.body = {
|
|
79601
|
+
code: 500,
|
|
79602
|
+
message: "查询最近录制片段失败",
|
|
79603
|
+
error: error?.message,
|
|
79604
|
+
};
|
|
79605
|
+
}
|
|
79606
|
+
});
|
|
79607
|
+
router$5.post("/danma-file", async (ctx) => {
|
|
79608
|
+
const { videoFilePath } = ctx.request.body;
|
|
79609
|
+
if (!videoFilePath) {
|
|
79610
|
+
ctx.status = 400;
|
|
79611
|
+
ctx.body = {
|
|
79612
|
+
code: 400,
|
|
79613
|
+
message: "videoFilePath不能为空",
|
|
79614
|
+
};
|
|
79615
|
+
return;
|
|
79616
|
+
}
|
|
79617
|
+
if (!(await index.fs.pathExists(videoFilePath))) {
|
|
79618
|
+
ctx.status = 404;
|
|
79619
|
+
ctx.body = {
|
|
79620
|
+
code: 404,
|
|
79621
|
+
message: "视频文件不存在",
|
|
79622
|
+
};
|
|
79623
|
+
return;
|
|
79624
|
+
}
|
|
79625
|
+
ctx.body = await createDanmaFileResponse(videoFilePath);
|
|
79626
|
+
});
|
|
79627
|
+
|
|
79628
|
+
const upload = multer({ dest: os$1.tmpdir() });
|
|
79629
|
+
const router$4 = new Router$1({
|
|
79630
|
+
prefix: "/files",
|
|
79631
|
+
});
|
|
79632
|
+
const DELETE_DIRS_ENV = "BILILIVE_TOOLS_DELETE_DIRS";
|
|
79633
|
+
const videoExts = new Set([".flv", ".mp4", ".ts", ".mkv", ".webm", ".m4v", ".m4s"]);
|
|
79634
|
+
const danmakuExts = new Set([".ass", ".xml", ".srt"]);
|
|
79635
|
+
function normalizePath(inputPath) {
|
|
79636
|
+
return path$7.resolve(inputPath);
|
|
79637
|
+
}
|
|
79638
|
+
function normalizeForCompare(inputPath) {
|
|
79639
|
+
const resolved = normalizePath(inputPath);
|
|
79640
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
79641
|
+
}
|
|
79642
|
+
function isSubPath(targetPath, rootPath) {
|
|
79643
|
+
const normalizedTarget = normalizeForCompare(targetPath);
|
|
79644
|
+
const normalizedRoot = normalizeForCompare(rootPath);
|
|
79645
|
+
if (normalizedTarget === normalizedRoot) {
|
|
79646
|
+
return true;
|
|
79647
|
+
}
|
|
79648
|
+
const relative = path$7.relative(normalizedRoot, normalizedTarget);
|
|
79649
|
+
return relative !== "" && !relative.startsWith("..") && !path$7.isAbsolute(relative);
|
|
79650
|
+
}
|
|
79651
|
+
function getRootPath() {
|
|
79652
|
+
const webhookConfig = exports.appConfig.get("webhook");
|
|
79653
|
+
const recorderConfig = exports.appConfig.get("recorder");
|
|
79654
|
+
const rootPath = webhookConfig?.recoderFolder || recorderConfig?.savePath;
|
|
79655
|
+
if (!rootPath) {
|
|
79656
|
+
throw new Error("未配置录制目录");
|
|
79657
|
+
}
|
|
79658
|
+
return normalizePath(rootPath);
|
|
79659
|
+
}
|
|
79660
|
+
function getAllowedDeleteDirs() {
|
|
79661
|
+
const envValue = process.env[DELETE_DIRS_ENV] || "";
|
|
79662
|
+
return envValue
|
|
79663
|
+
.split(",")
|
|
79664
|
+
.map((item) => item.trim())
|
|
79665
|
+
.filter(Boolean)
|
|
79666
|
+
.map((item) => normalizePath(item));
|
|
79667
|
+
}
|
|
79668
|
+
function getFileKind(filePath) {
|
|
79669
|
+
const ext = path$7.extname(filePath).toLowerCase();
|
|
79670
|
+
if (videoExts.has(ext)) {
|
|
79671
|
+
return "video";
|
|
79672
|
+
}
|
|
79673
|
+
if (danmakuExts.has(ext)) {
|
|
79674
|
+
return "danmaku";
|
|
79675
|
+
}
|
|
79676
|
+
return null;
|
|
79677
|
+
}
|
|
79678
|
+
function canDeleteFile(filePath) {
|
|
79679
|
+
const fileKind = getFileKind(filePath);
|
|
79680
|
+
if (!fileKind) {
|
|
79681
|
+
return false;
|
|
79682
|
+
}
|
|
79683
|
+
const allowedDeleteDirs = getAllowedDeleteDirs();
|
|
79684
|
+
if (allowedDeleteDirs.length === 0) {
|
|
79685
|
+
return false;
|
|
79686
|
+
}
|
|
79687
|
+
return allowedDeleteDirs.some((dir) => isSubPath(filePath, dir));
|
|
79688
|
+
}
|
|
79689
|
+
async function ensureDirectory(dirPath) {
|
|
79690
|
+
if (!(await index.fs.pathExists(dirPath))) {
|
|
79691
|
+
throw new Error("录制目录不存在");
|
|
79692
|
+
}
|
|
79693
|
+
const stat = await index.fs.stat(dirPath);
|
|
79694
|
+
if (!stat.isDirectory()) {
|
|
79695
|
+
throw new Error("录制目录无效");
|
|
79696
|
+
}
|
|
79697
|
+
}
|
|
79698
|
+
async function resolveBrowsePath(inputPath) {
|
|
79699
|
+
const rootPath = getRootPath();
|
|
79700
|
+
await ensureDirectory(rootPath);
|
|
79701
|
+
const currentPath = inputPath ? normalizePath(inputPath) : rootPath;
|
|
79702
|
+
if (!isSubPath(currentPath, rootPath)) {
|
|
79703
|
+
throw new Error("访问路径超出录制目录范围");
|
|
79704
|
+
}
|
|
79705
|
+
const stat = await index.fs.stat(currentPath).catch(() => null);
|
|
79706
|
+
if (!stat || !stat.isDirectory()) {
|
|
79707
|
+
throw new Error("目录不存在");
|
|
79708
|
+
}
|
|
79709
|
+
return {
|
|
79710
|
+
rootPath,
|
|
79711
|
+
currentPath,
|
|
79712
|
+
};
|
|
79713
|
+
}
|
|
79714
|
+
router$4.get("/list", async (ctx) => {
|
|
79715
|
+
const inputPath = ctx.query.path;
|
|
79716
|
+
const { rootPath, currentPath } = await resolveBrowsePath(inputPath);
|
|
79717
|
+
const names = await index.fs.readdir(currentPath);
|
|
79718
|
+
const items = [];
|
|
79719
|
+
for (const name of names) {
|
|
79720
|
+
const filePath = path$7.join(currentPath, name);
|
|
79721
|
+
const stat = await index.fs.stat(filePath).catch(() => null);
|
|
79722
|
+
if (!stat) {
|
|
79723
|
+
continue;
|
|
79724
|
+
}
|
|
79725
|
+
if (stat.isDirectory()) {
|
|
79726
|
+
items.push({
|
|
79727
|
+
name,
|
|
79728
|
+
path: filePath,
|
|
79729
|
+
type: "directory",
|
|
79730
|
+
mtimeMs: stat.mtimeMs,
|
|
79731
|
+
canDelete: false,
|
|
79732
|
+
});
|
|
79733
|
+
continue;
|
|
79734
|
+
}
|
|
79735
|
+
const fileKind = getFileKind(filePath);
|
|
79736
|
+
if (!fileKind) {
|
|
79737
|
+
continue;
|
|
79738
|
+
}
|
|
79739
|
+
items.push({
|
|
79740
|
+
name,
|
|
79741
|
+
path: filePath,
|
|
79742
|
+
type: "file",
|
|
79743
|
+
size: stat.size,
|
|
79744
|
+
mtimeMs: stat.mtimeMs,
|
|
79745
|
+
canDelete: canDeleteFile(filePath),
|
|
79746
|
+
fileKind,
|
|
79747
|
+
});
|
|
79748
|
+
}
|
|
79749
|
+
items.sort((left, right) => {
|
|
79750
|
+
if (left.type !== right.type) {
|
|
79751
|
+
return left.type === "directory" ? -1 : 1;
|
|
79752
|
+
}
|
|
79753
|
+
return left.name.localeCompare(right.name, "zh-CN");
|
|
79754
|
+
});
|
|
78557
79755
|
ctx.body = {
|
|
78558
|
-
|
|
78559
|
-
|
|
78560
|
-
|
|
78561
|
-
|
|
78562
|
-
|
|
78563
|
-
|
|
79756
|
+
rootPath,
|
|
79757
|
+
currentPath,
|
|
79758
|
+
parentPath: currentPath === rootPath ? null : path$7.dirname(currentPath),
|
|
79759
|
+
deleteEnabled: getAllowedDeleteDirs().length > 0,
|
|
79760
|
+
list: items,
|
|
79761
|
+
};
|
|
79762
|
+
});
|
|
79763
|
+
router$4.post("/download", async (ctx) => {
|
|
79764
|
+
const { path: filePath } = ctx.request.body;
|
|
79765
|
+
if (!filePath) {
|
|
79766
|
+
ctx.status = 400;
|
|
79767
|
+
ctx.body = { message: "文件路径不能为空" };
|
|
79768
|
+
return;
|
|
79769
|
+
}
|
|
79770
|
+
const { rootPath } = await resolveBrowsePath(path$7.dirname(filePath));
|
|
79771
|
+
const resolvedFilePath = normalizePath(filePath);
|
|
79772
|
+
if (!isSubPath(resolvedFilePath, rootPath)) {
|
|
79773
|
+
throw new Error("访问路径超出录制目录范围");
|
|
79774
|
+
}
|
|
79775
|
+
const stat = await index.fs.stat(resolvedFilePath).catch(() => null);
|
|
79776
|
+
if (!stat || !stat.isFile()) {
|
|
79777
|
+
throw new Error("文件不存在");
|
|
79778
|
+
}
|
|
79779
|
+
const fileKind = getFileKind(resolvedFilePath);
|
|
79780
|
+
if (!fileKind) {
|
|
79781
|
+
throw new Error("不支持下载该文件类型");
|
|
79782
|
+
}
|
|
79783
|
+
const fileId = fileCache.setFile(resolvedFilePath);
|
|
79784
|
+
ctx.body = {
|
|
79785
|
+
fileId,
|
|
79786
|
+
fileName: path$7.basename(resolvedFilePath),
|
|
79787
|
+
fileKind,
|
|
79788
|
+
};
|
|
79789
|
+
});
|
|
79790
|
+
router$4.post("/delete", async (ctx) => {
|
|
79791
|
+
const { path: filePath } = ctx.request.body;
|
|
79792
|
+
if (!filePath) {
|
|
79793
|
+
ctx.status = 400;
|
|
79794
|
+
ctx.body = { message: "文件路径不能为空" };
|
|
79795
|
+
return;
|
|
79796
|
+
}
|
|
79797
|
+
const resolvedFilePath = normalizePath(filePath);
|
|
79798
|
+
const { rootPath } = await resolveBrowsePath(path$7.dirname(resolvedFilePath));
|
|
79799
|
+
if (!isSubPath(resolvedFilePath, rootPath)) {
|
|
79800
|
+
throw new Error("访问路径超出录制目录范围");
|
|
79801
|
+
}
|
|
79802
|
+
const stat = await index.fs.stat(resolvedFilePath).catch(() => null);
|
|
79803
|
+
if (!stat || !stat.isFile()) {
|
|
79804
|
+
throw new Error("文件不存在");
|
|
79805
|
+
}
|
|
79806
|
+
const fileKind = getFileKind(resolvedFilePath);
|
|
79807
|
+
if (!fileKind) {
|
|
79808
|
+
throw new Error("仅支持删除视频和弹幕文件");
|
|
79809
|
+
}
|
|
79810
|
+
if (!canDeleteFile(resolvedFilePath)) {
|
|
79811
|
+
throw new Error(`当前未开启删除,或文件不在 ${DELETE_DIRS_ENV} 白名单目录中`);
|
|
79812
|
+
}
|
|
79813
|
+
await index.trashItem(resolvedFilePath);
|
|
79814
|
+
ctx.body = {
|
|
79815
|
+
message: "删除成功",
|
|
79816
|
+
path: resolvedFilePath,
|
|
79817
|
+
fileKind,
|
|
79818
|
+
};
|
|
79819
|
+
});
|
|
79820
|
+
router$4.post("/exists", async (ctx) => {
|
|
79821
|
+
const { filepath } = ctx.request.body;
|
|
79822
|
+
const exists = await index.fs.pathExists(filepath);
|
|
79823
|
+
ctx.body = exists;
|
|
79824
|
+
});
|
|
79825
|
+
router$4.post("/join", async (ctx) => {
|
|
79826
|
+
const { dir, name } = ctx.request.body;
|
|
79827
|
+
if (!index.fs.existsSync(dir)) {
|
|
79828
|
+
ctx.status = 400;
|
|
79829
|
+
ctx.body = "文件夹不存在";
|
|
79830
|
+
return;
|
|
79831
|
+
}
|
|
79832
|
+
const filePath = path$7.join(dir, name);
|
|
79833
|
+
ctx.body = filePath;
|
|
79834
|
+
});
|
|
79835
|
+
/**
|
|
79836
|
+
* @api {get} /files/temp 获取缓存文件夹路径
|
|
79837
|
+
* @apiDescription 获取当前配置的缓存文件夹路径
|
|
79838
|
+
* @apiSuccess {string} path 缓存文件夹路径
|
|
79839
|
+
*/
|
|
79840
|
+
router$4.get("/temp", async (ctx) => {
|
|
79841
|
+
try {
|
|
79842
|
+
const tempPath = index.getTempPath();
|
|
79843
|
+
ctx.body = tempPath;
|
|
79844
|
+
}
|
|
79845
|
+
catch (error) {
|
|
79846
|
+
console.error("获取缓存路径失败:", error);
|
|
79847
|
+
ctx.status = 500;
|
|
79848
|
+
ctx.body = "获取缓存路径失败";
|
|
79849
|
+
}
|
|
79850
|
+
});
|
|
79851
|
+
router$4.post("/cover/upload", upload.single("file"), async (ctx) => {
|
|
79852
|
+
const file = ctx.request?.file?.path;
|
|
79853
|
+
if (!file) {
|
|
79854
|
+
ctx.status = 400;
|
|
79855
|
+
ctx.body = "No file selected";
|
|
79856
|
+
return;
|
|
79857
|
+
}
|
|
79858
|
+
const originalname = ctx.request?.file?.originalname;
|
|
79859
|
+
const ext = path$7.extname(originalname);
|
|
79860
|
+
const coverPath = path$7.join(exports.config.userDataPath, "cover");
|
|
79861
|
+
const outputName = `${index.uuid()}${ext}`;
|
|
79862
|
+
// 将图片复制到指定目录
|
|
79863
|
+
await index.fs.ensureDir(coverPath);
|
|
79864
|
+
await index.fs.copyFile(file, path$7.join(coverPath, outputName));
|
|
79865
|
+
await index.fs.remove(file).catch(() => { });
|
|
79866
|
+
ctx.body = {
|
|
79867
|
+
name: outputName,
|
|
79868
|
+
path: `/assets/cover/${outputName}`,
|
|
78564
79869
|
};
|
|
78565
79870
|
});
|
|
78566
79871
|
|
|
@@ -78579,8 +79884,7 @@ function int2HexColor(color) {
|
|
|
78579
79884
|
}
|
|
78580
79885
|
return `#${hex}`;
|
|
78581
79886
|
}
|
|
78582
|
-
|
|
78583
|
-
const { filepath } = ctx.request.body;
|
|
79887
|
+
async function parseForArtPlayerData(filepath) {
|
|
78584
79888
|
const data = await index.parseDanmu(filepath);
|
|
78585
79889
|
const danmuList = [];
|
|
78586
79890
|
for (const item of data.danmu) {
|
|
@@ -78614,7 +79918,42 @@ router$3.post("/parseForArtPlayer", async (ctx) => {
|
|
|
78614
79918
|
style: {},
|
|
78615
79919
|
});
|
|
78616
79920
|
}
|
|
78617
|
-
|
|
79921
|
+
return danmuList;
|
|
79922
|
+
}
|
|
79923
|
+
router$3.get("/content/:id", async (ctx) => {
|
|
79924
|
+
const { id } = ctx.params;
|
|
79925
|
+
const file = fileCache.get(id);
|
|
79926
|
+
if (!file) {
|
|
79927
|
+
ctx.status = 404;
|
|
79928
|
+
ctx.body = { message: "弹幕文件不存在" };
|
|
79929
|
+
return;
|
|
79930
|
+
}
|
|
79931
|
+
if (!(await index.fs.pathExists(file.path))) {
|
|
79932
|
+
ctx.status = 404;
|
|
79933
|
+
ctx.body = { message: "弹幕文件不存在" };
|
|
79934
|
+
return;
|
|
79935
|
+
}
|
|
79936
|
+
const ext = path$7.extname(file.path).toLowerCase();
|
|
79937
|
+
if (ext === ".ass") {
|
|
79938
|
+
ctx.body = {
|
|
79939
|
+
danmaType: "ass",
|
|
79940
|
+
content: await index.fs.readFile(file.path, "utf-8"),
|
|
79941
|
+
};
|
|
79942
|
+
return;
|
|
79943
|
+
}
|
|
79944
|
+
if (ext === ".xml") {
|
|
79945
|
+
ctx.body = {
|
|
79946
|
+
danmaType: "xml",
|
|
79947
|
+
content: await parseForArtPlayerData(file.path),
|
|
79948
|
+
};
|
|
79949
|
+
return;
|
|
79950
|
+
}
|
|
79951
|
+
ctx.status = 400;
|
|
79952
|
+
ctx.body = { message: "不支持的弹幕格式" };
|
|
79953
|
+
});
|
|
79954
|
+
router$3.post("/parseForArtPlayer", async (ctx) => {
|
|
79955
|
+
const { filepath } = ctx.request.body;
|
|
79956
|
+
ctx.body = await parseForArtPlayerData(filepath);
|
|
78618
79957
|
});
|
|
78619
79958
|
|
|
78620
79959
|
const getConfig = (type) => {
|
|
@@ -79044,20 +80383,23 @@ async function subtitleRecognize(file, modelId, options) {
|
|
|
79044
80383
|
timeGapThreshold,
|
|
79045
80384
|
fillGap,
|
|
79046
80385
|
disableCache,
|
|
80386
|
+
song: options?.song,
|
|
79047
80387
|
});
|
|
79048
80388
|
try {
|
|
79049
80389
|
// 生成缓存路径
|
|
79050
80390
|
const cachePath = index.getTempPath();
|
|
79051
80391
|
const fileHash = await index.calculateFileQuickHash(file);
|
|
79052
|
-
// TODO:缓存有bug
|
|
80392
|
+
// TODO:缓存有bug,第二个是不同参数热词参数不同
|
|
79053
80393
|
const cacheFileName = `asr_subtitle_cache_${fileHash}_${modelId}.json`;
|
|
79054
80394
|
const cacheFilePath = path$7.join(cachePath, cacheFileName);
|
|
79055
80395
|
let asrResult = null;
|
|
79056
80396
|
// 尝试从缓存读取
|
|
79057
80397
|
if (!disableCache && (await index.fs.pathExists(cacheFilePath))) ;
|
|
79058
80398
|
if (!asrResult) {
|
|
79059
|
-
// 调用 ASR
|
|
79060
|
-
asrResult = await recognize$1(file, modelId
|
|
80399
|
+
// 调用 ASR 识别
|
|
80400
|
+
asrResult = await recognize$1(file, modelId, {
|
|
80401
|
+
filterMusic: options?.song ? false : true, // 启用音乐过滤
|
|
80402
|
+
});
|
|
79061
80403
|
// 保存到缓存(如果未禁用缓存)
|
|
79062
80404
|
if (!disableCache) ;
|
|
79063
80405
|
}
|
|
@@ -79186,6 +80528,7 @@ router$1.post("/subtitle", async (ctx) => {
|
|
|
79186
80528
|
const srt = await subtitleRecognize(audioFile, asrModelId, {
|
|
79187
80529
|
offset: data.offset,
|
|
79188
80530
|
disableCache: true,
|
|
80531
|
+
song: data.song,
|
|
79189
80532
|
});
|
|
79190
80533
|
// 清理临时音频文件
|
|
79191
80534
|
if (needCleanup) {
|
|
@@ -80165,7 +81508,7 @@ class LiveManager {
|
|
|
80165
81508
|
* 事件缓冲管理器
|
|
80166
81509
|
* 负责匹配 FileOpening 和 FileClosed 事件
|
|
80167
81510
|
*/
|
|
80168
|
-
class EventBufferManager extends EventEmitter$
|
|
81511
|
+
class EventBufferManager extends EventEmitter$4.EventEmitter {
|
|
80169
81512
|
// 事件缓冲区,同时保存 open 和 close 事件
|
|
80170
81513
|
events = new Map();
|
|
80171
81514
|
/**
|
|
@@ -80318,11 +81661,12 @@ class WebhookHandler {
|
|
|
80318
81661
|
index.logObj.info(`[EventBuffer] 处理匹配的事件对: ${pair.open.filePath}`);
|
|
80319
81662
|
const config = this.configManager.getConfig(pair.open.roomId);
|
|
80320
81663
|
if (!config.open) {
|
|
80321
|
-
index.logObj.
|
|
81664
|
+
index.logObj.warn(`${pair.open.roomId} is not open`);
|
|
80322
81665
|
return;
|
|
80323
81666
|
}
|
|
80324
81667
|
// 检查文件大小
|
|
80325
81668
|
if (!(await this.validateFileSize(config, pair.close))) {
|
|
81669
|
+
index.logObj.warn("文件大小不符合要求,跳过处理", pair.close.filePath);
|
|
80326
81670
|
return;
|
|
80327
81671
|
}
|
|
80328
81672
|
// 先处理 open 事件
|
|
@@ -80456,6 +81800,12 @@ class WebhookHandler {
|
|
|
80456
81800
|
* 验证文件大小
|
|
80457
81801
|
*/
|
|
80458
81802
|
async validateFileSize(config, options) {
|
|
81803
|
+
if (!config.minSize)
|
|
81804
|
+
return true;
|
|
81805
|
+
if (!(await index.fs.pathExists(options.filePath))) {
|
|
81806
|
+
index.logObj.warn(`文件不存在: ${options.filePath}`);
|
|
81807
|
+
return true;
|
|
81808
|
+
}
|
|
80459
81809
|
const fileSize = await index.getFileSize(options.filePath);
|
|
80460
81810
|
const fileSizeMB = fileSize / 1024 / 1024;
|
|
80461
81811
|
if (fileSizeMB >= config.minSize) {
|
|
@@ -81465,7 +82815,7 @@ exports.handler = void 0;
|
|
|
81465
82815
|
exports.appConfig = void 0;
|
|
81466
82816
|
exports.container = void 0;
|
|
81467
82817
|
const fileCache = createFileCache();
|
|
81468
|
-
path$7.dirname(require$$1$2.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-
|
|
82818
|
+
path$7.dirname(require$$1$2.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index-Czq88XrK.cjs', document.baseURI).href))));
|
|
81469
82819
|
const authMiddleware = (passKey) => {
|
|
81470
82820
|
return async (ctx, next) => {
|
|
81471
82821
|
const authHeader = ctx.headers["authorization"] || ctx.request.query.auth;
|
|
@@ -81502,8 +82852,8 @@ app.use(errorMiddleware);
|
|
|
81502
82852
|
app.use(cors$1());
|
|
81503
82853
|
app.use(bodyParserWrapper());
|
|
81504
82854
|
app.use(router.routes());
|
|
81505
|
-
app.use(router$
|
|
81506
|
-
app.use(router$
|
|
82855
|
+
app.use(router$h.routes());
|
|
82856
|
+
app.use(router$7.routes());
|
|
81507
82857
|
async function serverStart(options, axContainer) {
|
|
81508
82858
|
exports.container = axContainer;
|
|
81509
82859
|
exports.config = exports.container.resolve("globalConfig");
|
|
@@ -81514,20 +82864,21 @@ async function serverStart(options, axContainer) {
|
|
|
81514
82864
|
const auth = authMiddleware(passKey);
|
|
81515
82865
|
app.use(auth);
|
|
81516
82866
|
}
|
|
82867
|
+
app.use(router$g.routes());
|
|
81517
82868
|
app.use(router$f.routes());
|
|
82869
|
+
app.use(router$d.routes());
|
|
81518
82870
|
app.use(router$e.routes());
|
|
81519
82871
|
app.use(router$c.routes());
|
|
81520
|
-
app.use(router$
|
|
81521
|
-
app.use(router$b.routes());
|
|
82872
|
+
app.use(router$a.routes());
|
|
81522
82873
|
app.use(router$9.routes());
|
|
81523
82874
|
app.use(router$8.routes());
|
|
81524
|
-
app.use(router$
|
|
82875
|
+
app.use(router$6.routes());
|
|
81525
82876
|
app.use(router$5.routes());
|
|
81526
82877
|
app.use(router$4.routes());
|
|
81527
82878
|
app.use(router$3.routes());
|
|
81528
82879
|
app.use(router$2.routes());
|
|
81529
82880
|
app.use(router$1.routes());
|
|
81530
|
-
app.use(router$
|
|
82881
|
+
app.use(router$b.routes());
|
|
81531
82882
|
app.use(router.allowedMethods());
|
|
81532
82883
|
await createServer(options);
|
|
81533
82884
|
return app;
|
|
@@ -81549,6 +82900,12 @@ async function createServer(options) {
|
|
|
81549
82900
|
httpServer.on("error", (err) => {
|
|
81550
82901
|
index.logObj.error("HTTP 服务器错误:", err);
|
|
81551
82902
|
});
|
|
82903
|
+
httpServer.on("upgrade", (request, socket, head) => {
|
|
82904
|
+
if (handleRecorderUpgrade(request, socket, head)) {
|
|
82905
|
+
return;
|
|
82906
|
+
}
|
|
82907
|
+
socket.destroy();
|
|
82908
|
+
});
|
|
81552
82909
|
httpServer.listen(options.port, options.host, () => {
|
|
81553
82910
|
index.logObj.info(`Server is running at http://${options.host}:${options.port}`);
|
|
81554
82911
|
});
|