bililive-cli 3.14.0 → 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-DnN22ZAd.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;
@@ -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,
@@ -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) {
@@ -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');
@@ -56723,12 +57354,18 @@ router$e.get("/video/:videoId", async (ctx) => {
56723
57354
  ctx.body = file;
56724
57355
  }
56725
57356
  else {
57357
+ const MAX_CHUNK_SIZE = 1024 * 1024 * 1; // 1MB
56726
57358
  const head = {
56727
- "Content-Length": fileSize,
57359
+ "Content-Length": MAX_CHUNK_SIZE,
56728
57360
  "Content-Type": contentType,
57361
+ "Content-Range": `bytes 0-${Math.min(MAX_CHUNK_SIZE - 1, fileSize - 1)}/${fileSize}`,
57362
+ "Accept-Ranges": "bytes",
56729
57363
  };
56730
- ctx.res.writeHead(200, head);
56731
- 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;
56732
57369
  }
56733
57370
  });
56734
57371
  router$e.post("/parseDanmu", async (ctx) => {
@@ -57046,7 +57683,7 @@ router$d.post("/get_cookie", async (ctx) => {
57046
57683
  return;
57047
57684
  }
57048
57685
  const secret = "r96gkr8ahc34fsrewr34";
57049
- 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");
57050
57687
  if (hash !== signature) {
57051
57688
  ctx.status = 400;
57052
57689
  ctx.body = "签名无效";
@@ -57216,7 +57853,7 @@ var chokidar = {};
57216
57853
 
57217
57854
  var utils$7 = {};
57218
57855
 
57219
- const path$4 = require$$0$6;
57856
+ const path$4 = require$$0$7;
57220
57857
  const WIN_SLASH$1 = '\\\\/';
57221
57858
  const WIN_NO_SLASH$1 = `[^${WIN_SLASH$1}]`;
57222
57859
 
@@ -57396,7 +58033,7 @@ var constants$6 = {
57396
58033
 
57397
58034
  (function (exports) {
57398
58035
 
57399
- const path = require$$0$6;
58036
+ const path = require$$0$7;
57400
58037
  const win32 = process.platform === 'win32';
57401
58038
  const {
57402
58039
  REGEX_BACKSLASH,
@@ -58940,7 +59577,7 @@ parse$3.fastpaths = (input, options) => {
58940
59577
 
58941
59578
  var parse_1$1 = parse$3;
58942
59579
 
58943
- const path$3 = require$$0$6;
59580
+ const path$3 = require$$0$7;
58944
59581
  const scan$2 = scan_1$1;
58945
59582
  const parse$2 = parse_1$1;
58946
59583
  const utils$4 = utils$7;
@@ -59285,8 +59922,8 @@ var picomatch$4 = picomatch_1$1;
59285
59922
 
59286
59923
  const fs$3 = require$$0$8;
59287
59924
  const { Readable } = require$$0$9;
59288
- const sysPath$3 = require$$0$6;
59289
- const { promisify: promisify$3 } = require$$1$3;
59925
+ const sysPath$3 = require$$0$7;
59926
+ const { promisify: promisify$3 } = require$$1$4;
59290
59927
  const picomatch$3 = picomatch$4;
59291
59928
 
59292
59929
  const readdir$1 = promisify$3(fs$3.readdir);
@@ -59573,7 +60210,7 @@ var anymatch$2 = {exports: {}};
59573
60210
 
59574
60211
  var utils$3 = {};
59575
60212
 
59576
- const path$2 = require$$0$6;
60213
+ const path$2 = require$$0$7;
59577
60214
  const WIN_SLASH = '\\\\/';
59578
60215
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
59579
60216
 
@@ -59753,7 +60390,7 @@ var constants$3 = {
59753
60390
 
59754
60391
  (function (exports) {
59755
60392
 
59756
- const path = require$$0$6;
60393
+ const path = require$$0$7;
59757
60394
  const win32 = process.platform === 'win32';
59758
60395
  const {
59759
60396
  REGEX_BACKSLASH,
@@ -61297,7 +61934,7 @@ parse$1.fastpaths = (input, options) => {
61297
61934
 
61298
61935
  var parse_1 = parse$1;
61299
61936
 
61300
- const path$1 = require$$0$6;
61937
+ const path$1 = require$$0$7;
61301
61938
  const scan = scan_1;
61302
61939
  const parse = parse_1;
61303
61940
  const utils = utils$3;
@@ -62049,7 +62686,7 @@ var require$$0 = [
62049
62686
 
62050
62687
  var binaryExtensions$1 = require$$0;
62051
62688
 
62052
- const path = require$$0$6;
62689
+ const path = require$$0$7;
62053
62690
  const binaryExtensions = binaryExtensions$1;
62054
62691
 
62055
62692
  const extensions = new Set(binaryExtensions);
@@ -62060,7 +62697,7 @@ var constants = {};
62060
62697
 
62061
62698
  (function (exports) {
62062
62699
 
62063
- const {sep} = require$$0$6;
62700
+ const {sep} = require$$0$7;
62064
62701
  const {platform} = process;
62065
62702
  const os = require$$1$6;
62066
62703
 
@@ -62127,8 +62764,8 @@ var constants = {};
62127
62764
  } (constants));
62128
62765
 
62129
62766
  const fs$2 = require$$0$8;
62130
- const sysPath$2 = require$$0$6;
62131
- const { promisify: promisify$2 } = require$$1$3;
62767
+ const sysPath$2 = require$$0$7;
62768
+ const { promisify: promisify$2 } = require$$1$4;
62132
62769
  const isBinaryPath = isBinaryPath$1;
62133
62770
  const {
62134
62771
  isWindows: isWindows$1,
@@ -62778,8 +63415,8 @@ var nodefsHandler = NodeFsHandler$1;
62778
63415
  var fseventsHandler = {exports: {}};
62779
63416
 
62780
63417
  const fs$1 = require$$0$8;
62781
- const sysPath$1 = require$$0$6;
62782
- const { promisify: promisify$1 } = require$$1$3;
63418
+ const sysPath$1 = require$$0$7;
63419
+ const { promisify: promisify$1 } = require$$1$4;
62783
63420
 
62784
63421
  let fsevents;
62785
63422
  try {
@@ -63304,10 +63941,10 @@ fseventsHandler.exports.canUse = canUse;
63304
63941
 
63305
63942
  var fseventsHandlerExports = fseventsHandler.exports;
63306
63943
 
63307
- const { EventEmitter } = require$$0$7;
63944
+ const { EventEmitter } = require$$0$4;
63308
63945
  const fs = require$$0$8;
63309
- const sysPath = require$$0$6;
63310
- const { promisify } = require$$1$3;
63946
+ const sysPath = require$$0$7;
63947
+ const { promisify } = require$$1$4;
63311
63948
  const readdirp = readdirp_1;
63312
63949
  const anymatch = anymatchExports.default;
63313
63950
  const globParent = index.globParent;
@@ -64852,10 +65489,10 @@ class FFmpegWhisperASR {
64852
65489
  throw new Error(`音频文件不存在: ${filePath}`);
64853
65490
  }
64854
65491
  // 创建临时目录存放结果
64855
- 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");
64856
65493
  await index.fs.ensureDir(tempDir);
64857
65494
  // 生成唯一的输出文件名
64858
- const outputFile = require$$0$6.join(tempDir, `${v4()}.json`);
65495
+ const outputFile = require$$0$7.join(tempDir, `${v4()}.json`);
64859
65496
  try {
64860
65497
  // 执行 ffmpeg 命令
64861
65498
  await this.executeFFmpeg(filePath, outputFile);
@@ -65052,7 +65689,6 @@ class BCutASRAdapter {
65052
65689
  transformBCutResult(data, opts) {
65053
65690
  let list = data.utterances;
65054
65691
  if (opts?.filterMusic) {
65055
- // @ts-expect-error
65056
65692
  list = list.filter((s) => s.music <= 0.9); // 过滤掉标记为音乐的段落
65057
65693
  }
65058
65694
  let segments = list.map((utterance, index) => ({
@@ -72072,7 +72708,7 @@ class DecodedMessage {
72072
72708
  if (!uri.startsWith(DATA_URI_PREFIX)) {
72073
72709
  throw new Error('assert 4');
72074
72710
  }
72075
- 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'));
72076
72712
  }
72077
72713
  encodeToBinary() {
72078
72714
  const header = {
@@ -72123,7 +72759,7 @@ class DecodedMessage {
72123
72759
  }
72124
72760
  encodeToUri() {
72125
72761
  const bin = this.encodeToBinary();
72126
- 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');
72127
72763
  }
72128
72764
  }
72129
72765
 
@@ -76760,9 +77396,256 @@ router$b.get("/analyzerWaveform", sse({
76760
77396
  });
76761
77397
  });
76762
77398
 
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
+
76763
77515
  const router$a = new Router$1({
76764
77516
  prefix: "/recorder",
76765
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
+ };
76766
77649
  /**
76767
77650
  * 录制任务相关接口
76768
77651
  * @route GET /recorder/list
@@ -76780,6 +77663,58 @@ router$a.get("/list", async (ctx) => {
76780
77663
  const query = ctx.request.query;
76781
77664
  ctx.body = { payload: await recorderService.getRecorders(query) };
76782
77665
  });
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
+ });
76783
77718
  router$a.post("/add", async (ctx) => {
76784
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");
76785
77720
  const data = await recorderService.addRecorder(args);
@@ -76844,6 +77779,16 @@ router$a.post("/:id/cut", async (ctx) => {
76844
77779
  const { id } = ctx.params;
76845
77780
  ctx.body = { payload: await recorderService.cutRecord({ id }) };
76846
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
+ });
76847
77792
  /**
76848
77793
  * 批量开始录制
76849
77794
  * @route POST /recorder/manager/batch_start_record
@@ -76919,6 +77864,87 @@ router$a.post("/manager/liveInfo", async (ctx) => {
76919
77864
  payload: list,
76920
77865
  };
76921
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
+ }
76922
77948
 
76923
77949
  const router$9 = new Router$1({
76924
77950
  prefix: "/bili",
@@ -76980,16 +78006,6 @@ router$9.get("/platformArchiveDetail", async (ctx) => {
76980
78006
  const data = await index.biliApi.getPlatformArchiveDetail(aid, uid);
76981
78007
  ctx.body = data;
76982
78008
  });
76983
- router$9.get("/platformPre", async (ctx) => {
76984
- const { uid } = ctx.request.query;
76985
- const data = await index.biliApi.getPlatformPre(uid);
76986
- ctx.body = data;
76987
- });
76988
- router$9.get("/typeDesc", async (ctx) => {
76989
- const { tid, uid } = ctx.request.query;
76990
- const data = await index.biliApi.getTypeDesc(tid, uid);
76991
- ctx.body = data;
76992
- });
76993
78009
  /**
76994
78010
  * 上传以及续传视频
76995
78011
  */
@@ -77165,7 +78181,7 @@ async function flvRepair(input, output, opts) {
77165
78181
  index.taskQueue.addTask(task, true);
77166
78182
  return task;
77167
78183
  }
77168
- class MesioCommand extends EventEmitter$3 {
78184
+ class MesioCommand extends EventEmitter$4 {
77169
78185
  _input = "";
77170
78186
  _output = "";
77171
78187
  _inputOptions = [];
@@ -77243,7 +78259,7 @@ class MesioCommand extends EventEmitter$3 {
77243
78259
  }
77244
78260
  }
77245
78261
  }
77246
- class BililiveRecorderCommand extends EventEmitter$3 {
78262
+ class BililiveRecorderCommand extends EventEmitter$4 {
77247
78263
  _input = "";
77248
78264
  _output = "";
77249
78265
  _inputOptions = [];
@@ -77860,8 +78876,8 @@ async function download$1(output, url, options) {
77860
78876
  const mp4Output = index.replaceExtName(output, ".mp4");
77861
78877
  if ((await index.fs.pathExists(mp4Output)) && !options.override)
77862
78878
  throw new Error(`${mp4Output}已存在`);
77863
- const { dir, name } = require$$0$6.parse(output);
77864
- 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`);
77865
78881
  if (await index.fs.pathExists(tsOutput)) {
77866
78882
  throw new Error(`${tsOutput}已存在,您可以直接执行转封装命令,或者删除后重新下载`);
77867
78883
  }
@@ -77869,10 +78885,10 @@ async function download$1(output, url, options) {
77869
78885
  const downloader = new index.M3U8Downloader(url, tsOutput, {
77870
78886
  convert2Mp4: false,
77871
78887
  ffmpegPath: ffmpegPath,
77872
- segmentsDir: require$$0$6.join(index.getTempPath(), index.uuid()),
78888
+ segmentsDir: require$$0$7.join(index.getTempPath(), index.uuid()),
77873
78889
  });
77874
78890
  const task = new index.KuaishouDownloadVideoTask(downloader, {
77875
- name: `下载任务:${require$$0$6.parse(output).name}`,
78891
+ name: `下载任务:${require$$0$7.parse(output).name}`,
77876
78892
  }, {
77877
78893
  onEnd: async () => {
77878
78894
  const outputName = `${name}.mp4`;
@@ -77915,7 +78931,7 @@ var kuaishou = {
77915
78931
  var dist = {};
77916
78932
 
77917
78933
  (function (exports) {
77918
- 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);
77919
78935
  } (dist));
77920
78936
 
77921
78937
  async function download(output, url, options) {
@@ -78235,6 +79251,7 @@ async function downloadVideo(options) {
78235
79251
  live_start_time: options?.extra?.live_start_time,
78236
79252
  video_start_time: options?.extra?.video_start_time,
78237
79253
  });
79254
+ return;
78238
79255
  }
78239
79256
  await index.douyu.download(filepath, options?.extra?.decodeData, {
78240
79257
  danmu: options.danmu,
@@ -78344,11 +79361,23 @@ function extractBVNumber(videoUrl) {
78344
79361
  const router$5 = new Router$1({
78345
79362
  prefix: "/record-history",
78346
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
+ };
78347
79375
  /**
78348
79376
  * 查询直播记录
78349
79377
  * @route GET /record-history/list
78350
79378
  * @param {string} room_id - 房间号
78351
79379
  * @param {string} platform - 平台
79380
+ * @param {string} [liveId] - 直播ID
78352
79381
  * @param {number} [page=1] - 页码
78353
79382
  * @param {number} [pageSize=100] - 每页条数
78354
79383
  * @param {number} [startTime] - 开始时间(时间戳)
@@ -78356,7 +79385,7 @@ const router$5 = new Router$1({
78356
79385
  * @returns
78357
79386
  */
78358
79387
  router$5.get("/list", async (ctx) => {
78359
- const { room_id, platform, page, pageSize, startTime, endTime } = ctx.query;
79388
+ const { room_id, platform, liveId, page, pageSize, startTime, endTime } = ctx.query;
78360
79389
  if (!room_id || !platform) {
78361
79390
  ctx.status = 400;
78362
79391
  ctx.body = {
@@ -78369,6 +79398,7 @@ router$5.get("/list", async (ctx) => {
78369
79398
  const result = index.recordHistory.queryRecordsByRoomAndPlatform({
78370
79399
  room_id: room_id,
78371
79400
  platform: platform,
79401
+ liveId: liveId ? String(liveId) : undefined,
78372
79402
  page: page ? parseInt(page) : undefined,
78373
79403
  pageSize: pageSize ? parseInt(pageSize) : undefined,
78374
79404
  startTime: startTime ? parseInt(startTime) : undefined,
@@ -78458,6 +79488,16 @@ const getVideoFile = async (id) => {
78458
79488
  }
78459
79489
  return null;
78460
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
+ };
78461
79501
  /**
78462
79502
  * 获取弹幕文件路径,优先查询ass文件,其次查询xml文件
78463
79503
  * @param videoFile 视频文件路径
@@ -78503,25 +79543,67 @@ router$5.get("/file/:id", async (ctx) => {
78503
79543
  ctx.body = "视频文件不存在";
78504
79544
  return;
78505
79545
  }
78506
- const extname = path$7.extname(videoFile).toLowerCase();
78507
- const videoFileId = fileCache.setFile(videoFile);
78508
- let videoFileExt = "";
78509
- switch (extname) {
78510
- case ".flv":
78511
- videoFileExt = "flv";
78512
- break;
78513
- case ".ts":
78514
- videoFileExt = "ts";
78515
- break;
78516
- }
79546
+ const videoInfo = await createVideoFileResponse(videoFile);
78517
79547
  const danmaInfo = await createDanmaFileResponse(videoFile);
78518
79548
  ctx.body = {
78519
- videoFilePath: videoFile,
78520
- videoFileId,
78521
- videoFileExt,
79549
+ ...videoInfo,
78522
79550
  ...danmaInfo,
78523
79551
  };
78524
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;
79562
+ }
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
+ };
79597
+ }
79598
+ catch (error) {
79599
+ ctx.status = 500;
79600
+ ctx.body = {
79601
+ code: 500,
79602
+ message: "查询最近录制片段失败",
79603
+ error: error?.message,
79604
+ };
79605
+ }
79606
+ });
78525
79607
  router$5.post("/danma-file", async (ctx) => {
78526
79608
  const { videoFilePath } = ctx.request.body;
78527
79609
  if (!videoFilePath) {
@@ -80426,7 +81508,7 @@ class LiveManager {
80426
81508
  * 事件缓冲管理器
80427
81509
  * 负责匹配 FileOpening 和 FileClosed 事件
80428
81510
  */
80429
- class EventBufferManager extends EventEmitter$3.EventEmitter {
81511
+ class EventBufferManager extends EventEmitter$4.EventEmitter {
80430
81512
  // 事件缓冲区,同时保存 open 和 close 事件
80431
81513
  events = new Map();
80432
81514
  /**
@@ -81733,7 +82815,7 @@ exports.handler = void 0;
81733
82815
  exports.appConfig = void 0;
81734
82816
  exports.container = void 0;
81735
82817
  const fileCache = createFileCache();
81736
- 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-BxJPCbAG.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))));
81737
82819
  const authMiddleware = (passKey) => {
81738
82820
  return async (ctx, next) => {
81739
82821
  const authHeader = ctx.headers["authorization"] || ctx.request.query.auth;
@@ -81818,6 +82900,12 @@ async function createServer(options) {
81818
82900
  httpServer.on("error", (err) => {
81819
82901
  index.logObj.error("HTTP 服务器错误:", err);
81820
82902
  });
82903
+ httpServer.on("upgrade", (request, socket, head) => {
82904
+ if (handleRecorderUpgrade(request, socket, head)) {
82905
+ return;
82906
+ }
82907
+ socket.destroy();
82908
+ });
81821
82909
  httpServer.listen(options.port, options.host, () => {
81822
82910
  index.logObj.info(`Server is running at http://${options.host}:${options.port}`);
81823
82911
  });