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-CgpPN0zA.cjs');
8
- var require$$0$4 = require('tty');
9
- var require$$1$3 = require('util');
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$6 = require('path');
12
- var require$$0$5 = require('buffer');
13
- var require$$0$7 = require('events');
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$4 = require('crypto');
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$3 = require('node:events');
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$4;
2126
- const util = require$$1$3;
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$5;
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$6.basename;
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$7.EventEmitter;
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$6.extname;
5235
+ const extname = require$$0$7.extname;
4635
5236
  const vary = varyExports;
4636
5237
  const only = only$1;
4637
- const util = require$$1$3;
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$7.EventEmitter;
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$6.relative;
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$7.EventEmitter;
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$6.relative;
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$6.relative;
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$4;
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$4;
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$3;
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$3;
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$7;
11656
- const util$2 = require$$1$3;
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$h = Router;
14572
+ var router$i = Router;
13972
14573
 
13973
- var Router$1 = /*@__PURE__*/index.getDefaultExportFromCjs(router$h);
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$5;
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$5.Buffer,
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$5.Buffer;
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$5.SlowBuffer;
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$5.SlowBuffer;
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$3.inspect;
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$g = new Router$1();
30886
- router$g.get("/webhook", async (ctx) => {
31516
+ const router$h = new Router$1();
31517
+ router$h.get("/webhook", async (ctx) => {
30887
31518
  ctx.body = "webhook 服务器已启动";
30888
31519
  });
30889
- router$g.post("/webhook/bililiverecorder", async (ctx) => {
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$g.post("/webhook/blrec", async (ctx) => {
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$g.post("/webhook/oneliverec", async (ctx) => {
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$g.post("/webhook/ddtv", async (ctx) => {
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$g.post("/webhook/custom", async (ctx) => {
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$g.get("/bili/stream", async (ctx) => {
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$5;
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$5.Buffer.isBuffer;
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$3;
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$3.deprecate;
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$5;
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$7.EventEmitter;
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$3;
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$7.EventEmitter;
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$3;
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$6;
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$6;
48016
- var crypto$1 = require$$1$4;
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$f = new Router$1({
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$f.get("/", async (ctx) => {
49746
+ router$g.get("/", async (ctx) => {
49116
49747
  const config = exports.appConfig.getAll();
49117
49748
  ctx.body = config;
49118
49749
  });
49119
- router$f.post("/", async (ctx) => {
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$f.post("/set", async (ctx) => {
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$f.post("/verifyBiliKey", async (ctx) => {
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$f.post("/resetBin", async (ctx) => {
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$f.get("/export", async (ctx) => {
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$f.post("/import", upload$1.single("file"), async (ctx) => {
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$f.post("/notifyTest", async (ctx) => {
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$6.resolve(image));
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$6.join(require$$1$6.homedir(), inputPath.slice(1));
51073
+ return require$$0$7.join(require$$1$6.homedir(), inputPath.slice(1));
50443
51074
  }
50444
- return require$$0$6.resolve(mfDir, inputPath);
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$4.createHash("sha256");
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$6.dirname(request.path)
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$5,
51285
+ var _require = require$$0$6,
50655
51286
  Buffer = _require.Buffer;
50656
- var _require2 = require$$1$3,
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$5.Buffer;
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$7.EventEmitter;
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$5.Buffer;
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$3;
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$e = new Router$1({
54751
+ const router$f = new Router$1({
54121
54752
  prefix: "/llm",
54122
54753
  });
54123
- router$e.get("/ollama/modelList", async (ctx) => {
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$e.post("/translate", async (ctx) => {
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$d = new Router$1({
57070
+ const router$e = new Router$1({
56440
57071
  prefix: "/common",
56441
57072
  });
56442
- const upload = multer({ dest: os$1.tmpdir() });
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$d.get("/files", async (ctx) => {
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$d.post("/fileJoin", async (ctx) => {
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$d.post("/parseVideoMetadata", async (ctx) => {
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$d.get("/fonts", async (ctx) => {
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$d.post("/cover/upload", upload.single("file"), async (ctx) => {
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$d.get("/statistics", async (ctx) => {
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$d.get("/exportLogs", async (ctx) => {
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$d.get("/getLogContent", async (ctx) => {
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$d.post("/readDanma", async (ctx) => {
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$d.post("/readLLC", async (ctx) => {
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$d.post("/writeLLC", async (ctx) => {
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$d.post("/fileExists", async (ctx) => {
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$d.post("/apply-video-id", async (ctx) => {
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$d.get("/video/:videoId", async (ctx) => {
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": fileSize,
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(200, head);
56766
- ctx.body = index.fs.createReadStream(videoPath);
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$d.post("/parseDanmu", async (ctx) => {
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$d.post("/testWebhook", async (ctx) => {
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$d.post("/handleWebhook", async (ctx) => {
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$d.post("/webhook", async (ctx) => {
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$d.get("/whyUploadFailed", async (ctx) => {
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$d.get("/checkUpdate", async (ctx) => {
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$d.get("/diskSpace", async (ctx) => {
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$c = new Router$1({
57648
+ const router$d = new Router$1({
57063
57649
  prefix: "/user",
57064
57650
  });
57065
- router$c.get("/list", async (ctx) => {
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$c.post("/delete", async (ctx) => {
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$c.post("/update", async (ctx) => {
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$c.post("/update_auth", async (ctx) => {
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$c.post("/get_cookie", async (ctx) => {
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$4.createHmac("sha256", secret).update(`${uid}${timestamp}`).digest("hex");
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$c.get("/export", async (ctx) => {
57708
+ router$d.get("/export", async (ctx) => {
57123
57709
  const list = index.biliApi.readUserList();
57124
57710
  ctx.body = list;
57125
57711
  });
57126
- router$c.post("/export_single", async (ctx) => {
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$c.post("/import", async (ctx) => {
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$c.post("/import_single", async (ctx) => {
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$b = new Router$1({
57750
+ const router$c = new Router$1({
57165
57751
  prefix: "/preset",
57166
57752
  });
57167
57753
  ////////////////// 弹幕预设 ///////////////////////////////
57168
- router$b.get("/danmu", async (ctx) => {
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$b.get("/danmu/:id", async (ctx) => {
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$b.post("/danmu", async (ctx) => {
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$b.del("/danmu/:id", async (ctx) => {
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$b.put("/danmu/:id", async (ctx) => {
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$b.get("/video", async (ctx) => {
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$b.get("/video/:id", async (ctx) => {
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$b.post("/video", async (ctx) => {
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$b.del("/video/:id", async (ctx) => {
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$b.put("/video/:id", async (ctx) => {
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$b.get("/ffmpeg", async (ctx) => {
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$b.get("/ffmpeg/options", async (ctx) => {
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$b.get("/ffmpeg/:id", async (ctx) => {
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$b.post("/ffmpeg", async (ctx) => {
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$b.del("/ffmpeg/:id", async (ctx) => {
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$b.put("/ffmpeg/:id", async (ctx) => {
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$b.get("/subtitle-style", async (ctx) => {
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$b.get("/subtitle-style/:id", async (ctx) => {
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$b.post("/subtitle-style", async (ctx) => {
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$b.del("/subtitle-style/:id", async (ctx) => {
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$b.put("/subtitle-style/:id", async (ctx) => {
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$6;
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$6;
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$6;
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$6;
59340
- const { promisify: promisify$3 } = require$$1$3;
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$6;
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$6;
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$6;
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$2 = function(path, stripTrailing) {
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$1 = normalizePath$2;
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$1(_path, false);
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$6;
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$6;
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$6;
62182
- const { promisify: promisify$2 } = require$$1$3;
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$6;
62833
- const { promisify: promisify$1 } = require$$1$3;
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$7;
63944
+ const { EventEmitter } = require$$0$4;
63359
63945
  const fs = require$$0$8;
63360
- const sysPath = require$$0$6;
63361
- const { promisify } = require$$1$3;
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$2;
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$6.join(require$$1$6.tmpdir(), "whisper-asr");
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$6.join(tempDir, `${v4()}.json`);
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
- // 这里需要根据 B接口 ASR 的实际返回格式进行转换,以下是一个示例结构
65105
- const segments = data.utterances.map((utterance, index) => ({
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$5.Buffer.from(uri.replace(DATA_URI_PREFIX, ''), 'base64'));
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$5.Buffer.from(bin).toString('base64');
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$a = new Router$1({
77249
+ const router$b = new Router$1({
76661
77250
  prefix: "/sse",
76662
77251
  });
76663
77252
  /**
76664
77253
  * 流式查询日志
76665
77254
  */
76666
- router$a.get("/streamLogs", sse({
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$a.get("/recorder/danma", sse({
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$a.get("/task/runningNum", sse({
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$a.get("/analyzerWaveform", sse({
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 router$9 = new Router$1({
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$9.get("/list", async (ctx) => {
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$9.post("/add", async (ctx) => {
76831
- const args = index.pick((ctx.request.body ?? {}), "providerId", "channelId", "remarks", "disableAutoCheck", "quality", "streamPriorities", "sourcePriorities", "extra", "noGlobalFollowFields", "line", "disableProvideCommentsWhenRecording", "saveGiftDanma", "saveSCDanma", "segment", "sendToWebhook", "uid", "saveCover", "qualityRetry", "formatName", "useM3U8Proxy", "customHost", "codecName", "titleKeywords", "liveStartNotification", "liveEndNotification", "weight", "source", "videoFormat", "recorderType", "cookie", "doubleScreen", "onlyAudio", "useServerTimestamp", "handleTime", "debugLevel", "api");
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$9.get("/:id", (ctx) => {
77729
+ router$a.get("/:id", (ctx) => {
76842
77730
  const { id } = ctx.params;
76843
77731
  ctx.body = { payload: recorderService.getRecorder({ id }) };
76844
77732
  });
76845
- router$9.put("/:id", (ctx) => {
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$9.delete("/:id", (ctx) => {
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$9.post("/:id/start_record", async (ctx) => {
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$9.post("/:id/stop_record", async (ctx) => {
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$9.post("/:id/cut", async (ctx) => {
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$9.post("/manager/batch_start_record", async (ctx) => {
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$9.post("/manager/batch_stop_record", async (ctx) => {
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$9.get("/manager/resolveChannel", async (ctx) => {
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$9.get("/manager/resolve", async (ctx) => {
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$9.post("/manager/batchResolveChannel", async (ctx) => {
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$9.post("/manager/liveInfo", async (ctx) => {
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$8 = new Router$1({
77949
+ const router$9 = new Router$1({
76971
77950
  prefix: "/bili",
76972
77951
  });
76973
77952
  // 验证视频上传参数
76974
- router$8.post("/validUploadParams", async (ctx) => {
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$8.get("/archives", async (ctx) => {
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$8.get("/user/archive/:bvid", async (ctx) => {
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$8.post("/checkTag", async (ctx) => {
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$8.get("/searchTopic", async (ctx) => {
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$8.get("/seasons", async (ctx) => {
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$8.get("/season/:aid", async (ctx) => {
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$8.get("/platformArchiveDetail", async (ctx) => {
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$8.post("/upload", async (ctx) => {
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$8.post("/login", async (ctx) => {
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$8.post("/login/cancel", async (ctx) => {
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$8.get("/login/poll", async (ctx) => {
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$8.post("/formatTitle", async (ctx) => {
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$8.post("/formatPartTitle", async (ctx) => {
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$8.post("/formatDesc", async (ctx) => {
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$3 {
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$3 {
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$7 = new Router$1({
78406
+ const router$8 = new Router$1({
77438
78407
  prefix: "/task",
77439
78408
  });
77440
- router$7.get("/", async (ctx) => {
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$7.get("/:id", async (ctx) => {
78420
+ router$8.get("/:id", async (ctx) => {
77452
78421
  const { id } = ctx.params;
77453
78422
  ctx.body = index.handleQueryTask(id);
77454
78423
  });
77455
- router$7.post("/:id/pause", async (ctx) => {
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$7.post("/:id/resume", async (ctx) => {
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$7.post("/:id/kill", async (ctx) => {
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$7.post("/:id/interrupt", async (ctx) => {
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$7.post("/:id/removeRecord", async (ctx) => {
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$7.post("/:id/restart", async (ctx) => {
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$7.post("/:id/removeFile", async (ctx) => {
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$7.post("/:id/start", async (ctx) => {
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$7.post("/removeBatch", async (ctx) => {
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$7.post("/videoMeta", async (ctx) => {
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$7.post("/convertXml2Ass", async (ctx) => {
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$7.post("/checkMergeVideos", async (ctx) => {
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$7.post("/mergeVideo", async (ctx) => {
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$7.post("/transcode", async (ctx) => {
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$7.post("/burn", async (ctx) => {
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$7.post("/flvRepair", async (ctx) => {
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$7.post("/cut", async (ctx) => {
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$7.post("/cutSubtitle", async (ctx) => {
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$7.post("/addExtraVideoTask", async (ctx) => {
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$7.post("/editVideoPartName", async (ctx) => {
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$7.post("/queryVideoStatus", async (ctx) => {
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$7.get("/:id/download", async (ctx) => {
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$7.post("/testVirtualRecord", async (ctx) => {
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$7.post("/executeVirtualRecord", async (ctx) => {
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$7.post("/extractPeaks", async (ctx) => {
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$7.post("/analyzerWaveform", async (ctx) => {
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$6 = new Router$1({
78840
+ const router$7 = new Router$1({
77872
78841
  prefix: "/assets",
77873
78842
  });
77874
- router$6.get("/cover/:filename", async (ctx) => {
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$6.get("/download/:id", async (ctx) => {
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$6.parse(output);
77911
- const tsOutput = require$$0$6.join(dir, `${name}.ts`);
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$6.join(index.getTempPath(), index.uuid()),
78888
+ segmentsDir: require$$0$7.join(index.getTempPath(), index.uuid()),
77920
78889
  });
77921
78890
  const task = new index.KuaishouDownloadVideoTask(downloader, {
77922
- name: `下载任务:${require$$0$6.parse(output).name}`,
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$5 = new Router$1({
78989
+ const router$6 = new Router$1({
78021
78990
  prefix: "/video",
78022
78991
  });
78023
- router$5.post("/parse", async (ctx) => {
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$5.post("/download", async (ctx) => {
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$5.post("/sub/parse", async (ctx) => {
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$5.post("/sub/add", async (ctx) => {
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$5.post("/sub/remove", async (ctx) => {
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$5.post("/sub/update", async (ctx) => {
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$5.get("/sub/list", async (ctx) => {
79033
+ router$6.get("/sub/list", async (ctx) => {
78065
79034
  const res = index.videoSub.list();
78066
79035
  ctx.body = res;
78067
79036
  });
78068
- router$5.post("/sub/check", async (ctx) => {
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$4 = new Router$1({
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$4.get("/list", async (ctx) => {
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$4.delete("/:id", async (ctx) => {
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$4.get("/file/:id", async (ctx) => {
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 extname = path$7.extname(videoFile).toLowerCase();
78542
- const videoFileId = fileCache.setFile(videoFile);
78543
- let videoFileExt = "";
78544
- switch (extname) {
78545
- case ".flv":
78546
- videoFileExt = "flv";
78547
- break;
78548
- case ".ts":
78549
- videoFileExt = "ts";
78550
- break;
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
- const danmaFile = await getDanmaFile(videoFile);
78553
- let danmaFileId = null;
78554
- if (danmaFile) {
78555
- danmaFileId = fileCache.setFile(danmaFile.file);
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
- videoFilePath: videoFile,
78559
- videoFileId,
78560
- videoFileExt,
78561
- danmaFilePath: danmaFile?.file || null,
78562
- danmaFileId,
78563
- danmaFileExt: danmaFile?.ext || null,
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
- router$3.post("/parseForArtPlayer", async (ctx) => {
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
- ctx.body = danmuList;
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$3.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.info(`${pair.open.roomId} is not open`);
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-DG03bxlI.cjs', document.baseURI).href))));
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$g.routes());
81506
- app.use(router$6.routes());
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$d.routes());
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$7.routes());
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$a.routes());
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
  });