@tiny-codes/react-easy 1.4.8 → 1.4.9
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.
- package/CHANGELOG.md +22 -0
- package/es/hooks/index.d.ts +3 -0
- package/es/hooks/index.js +3 -0
- package/es/hooks/index.js.map +1 -1
- package/es/hooks/useAudioPlayer.d.ts +7 -0
- package/es/hooks/useAudioPlayer.js +13 -0
- package/es/hooks/useAudioPlayer.js.map +1 -0
- package/es/hooks/useSSE.d.ts +26 -0
- package/es/hooks/useSSE.js +147 -0
- package/es/hooks/useSSE.js.map +1 -0
- package/es/utils/AudioPlayer.d.ts +159 -0
- package/es/utils/AudioPlayer.js +433 -0
- package/es/utils/AudioPlayer.js.map +1 -0
- package/es/utils/base64.d.ts +48 -0
- package/es/utils/base64.js +139 -0
- package/es/utils/base64.js.map +1 -0
- package/es/utils/crypto.d.ts +0 -30
- package/es/utils/crypto.js +8 -93
- package/es/utils/crypto.js.map +1 -1
- package/es/utils/index.d.ts +5 -1
- package/es/utils/index.js +5 -1
- package/es/utils/index.js.map +1 -1
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.js +8 -0
- package/lib/hooks/index.js.map +2 -2
- package/lib/hooks/useAudioPlayer.d.ts +7 -0
- package/lib/hooks/useAudioPlayer.js +42 -0
- package/lib/hooks/useAudioPlayer.js.map +7 -0
- package/lib/hooks/useSSE.d.ts +26 -0
- package/lib/hooks/useSSE.js +128 -0
- package/lib/hooks/useSSE.js.map +7 -0
- package/lib/utils/AudioPlayer.d.ts +159 -0
- package/lib/utils/AudioPlayer.js +284 -0
- package/lib/utils/AudioPlayer.js.map +7 -0
- package/lib/utils/base64.d.ts +48 -0
- package/lib/utils/base64.js +120 -0
- package/lib/utils/base64.js.map +7 -0
- package/lib/utils/crypto.d.ts +0 -30
- package/lib/utils/crypto.js +7 -66
- package/lib/utils/crypto.js.map +2 -2
- package/lib/utils/index.d.ts +5 -1
- package/lib/utils/index.js +28 -3
- package/lib/utils/index.js.map +2 -2
- package/package.json +2 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import AudioPlayer, { type AudioPlayerInit } from '../utils/AudioPlayer';
|
|
2
|
+
/**
|
|
3
|
+
* - **EN:** A hook that provides an instance of the AudioPlayer class for managing audio playback.
|
|
4
|
+
* - **CN:** 一个提供AudioPlayer类实例的钩子,用于管理音频播放。
|
|
5
|
+
*/
|
|
6
|
+
declare const useAudioPlayer: (props?: AudioPlayerInit) => AudioPlayer;
|
|
7
|
+
export default useAudioPlayer;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/hooks/useAudioPlayer.ts
|
|
30
|
+
var useAudioPlayer_exports = {};
|
|
31
|
+
__export(useAudioPlayer_exports, {
|
|
32
|
+
default: () => useAudioPlayer_default
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(useAudioPlayer_exports);
|
|
35
|
+
var import_react = require("react");
|
|
36
|
+
var import_AudioPlayer = __toESM(require("../utils/AudioPlayer"));
|
|
37
|
+
var useAudioPlayer = (props) => {
|
|
38
|
+
const ref = (0, import_react.useRef)(new import_AudioPlayer.default(props));
|
|
39
|
+
return ref.current;
|
|
40
|
+
};
|
|
41
|
+
var useAudioPlayer_default = useAudioPlayer;
|
|
42
|
+
//# sourceMappingURL=useAudioPlayer.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/hooks/useAudioPlayer.ts"],
|
|
4
|
+
"sourcesContent": ["import { useRef } from 'react';\nimport AudioPlayer, { type AudioPlayerInit } from '../utils/AudioPlayer';\n\n/**\n * - **EN:** A hook that provides an instance of the AudioPlayer class for managing audio playback.\n * - **CN:** 一个提供AudioPlayer类实例的钩子,用于管理音频播放。\n */\nconst useAudioPlayer = (props?: AudioPlayerInit): AudioPlayer => {\n const ref = useRef<AudioPlayer>(new AudioPlayer(props));\n return ref.current;\n};\n\nexport default useAudioPlayer;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAuB;AACvB,yBAAkD;AAMlD,IAAM,iBAAiB,CAAC,UAAyC;AAC/D,QAAM,UAAM,qBAAoB,IAAI,mBAAAA,QAAY,KAAK,CAAC;AACtD,SAAO,IAAI;AACb;AAEA,IAAO,yBAAQ;",
|
|
6
|
+
"names": ["AudioPlayer"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { EventSourceMessage, FetchEventSourceInit } from '@microsoft/fetch-event-source';
|
|
2
|
+
export interface UseSSEProps<T = any> {
|
|
3
|
+
/** The URL to connect to */
|
|
4
|
+
url: RequestInfo;
|
|
5
|
+
/** Options for the connection. */
|
|
6
|
+
connectOptions?: Omit<FetchEventSourceInit, 'onmessage' | 'onerror' | 'onclose'>;
|
|
7
|
+
/** Automatically connect to the SSE channel. Default is `false`. */
|
|
8
|
+
autoConnect?: boolean;
|
|
9
|
+
/** Automatically close the connection when the component unmounts. Default is `true`. */
|
|
10
|
+
autoClose?: boolean;
|
|
11
|
+
/** Function to parse the incoming message. If not provided, the default JSON parser will be used. */
|
|
12
|
+
parseMessage?: (original: EventSourceMessage) => T;
|
|
13
|
+
/** Callback function to handle incoming messages. */
|
|
14
|
+
onMessage?: (messageData: T) => void;
|
|
15
|
+
/** Callback function to handle errors. */
|
|
16
|
+
onError?: (error: any) => void;
|
|
17
|
+
/** Callback function to handle connection closure. */
|
|
18
|
+
onClose?: () => void;
|
|
19
|
+
}
|
|
20
|
+
declare const useSSE: <T = any>(props: UseSSEProps<T>) => {
|
|
21
|
+
connect: (options?: FetchEventSourceInit & Partial<Pick<UseSSEProps, 'url'>>) => Promise<void>;
|
|
22
|
+
close: () => void;
|
|
23
|
+
isRequesting: boolean;
|
|
24
|
+
isConnected: boolean;
|
|
25
|
+
};
|
|
26
|
+
export default useSSE;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/hooks/useSSE.ts
|
|
30
|
+
var useSSE_exports = {};
|
|
31
|
+
__export(useSSE_exports, {
|
|
32
|
+
default: () => useSSE_default
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(useSSE_exports);
|
|
35
|
+
var import_react = require("react");
|
|
36
|
+
var import_fetch_event_source = require("@microsoft/fetch-event-source");
|
|
37
|
+
var import_useRefFunction = __toESM(require("./useRefFunction"));
|
|
38
|
+
var import_useRefValue = __toESM(require("./useRefValue"));
|
|
39
|
+
var useSSE = (props) => {
|
|
40
|
+
const { url, autoConnect, connectOptions, onMessage, parseMessage, onError, onClose } = props;
|
|
41
|
+
const autoConnectRef = (0, import_useRefValue.default)(autoConnect);
|
|
42
|
+
const [isRequesting, setIsRequesting] = (0, import_react.useState)(false);
|
|
43
|
+
const isRequestingRef = (0, import_useRefValue.default)(isRequesting);
|
|
44
|
+
const [isConnected, setIsConnected] = (0, import_react.useState)(false);
|
|
45
|
+
const abortCtrlRef = (0, import_react.useRef)(void 0);
|
|
46
|
+
const connect = (0, import_useRefFunction.default)(async (options) => {
|
|
47
|
+
const {
|
|
48
|
+
url: connectUrl = url,
|
|
49
|
+
headers = {},
|
|
50
|
+
onopen,
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
52
|
+
onmessage,
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
54
|
+
onclose,
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
56
|
+
onerror,
|
|
57
|
+
...restOptions
|
|
58
|
+
} = { ...connectOptions, ...options };
|
|
59
|
+
abortCtrlRef.current = new AbortController();
|
|
60
|
+
try {
|
|
61
|
+
setIsRequesting(true);
|
|
62
|
+
setIsConnected(false);
|
|
63
|
+
await (0, import_fetch_event_source.fetchEventSource)(connectUrl, {
|
|
64
|
+
method: "post",
|
|
65
|
+
signal: abortCtrlRef.current.signal,
|
|
66
|
+
openWhenHidden: true,
|
|
67
|
+
onopen: async (response) => {
|
|
68
|
+
setIsConnected(true);
|
|
69
|
+
onopen == null ? void 0 : onopen(response);
|
|
70
|
+
},
|
|
71
|
+
onmessage(event) {
|
|
72
|
+
if (!isRequestingRef.current) {
|
|
73
|
+
setIsRequesting(false);
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
let parsed;
|
|
77
|
+
if (parseMessage) {
|
|
78
|
+
parsed = parseMessage(event);
|
|
79
|
+
} else {
|
|
80
|
+
parsed = event.data ? JSON.parse(event.data) : void 0;
|
|
81
|
+
}
|
|
82
|
+
if (parsed != null) {
|
|
83
|
+
onMessage == null ? void 0 : onMessage(parsed);
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error("Error parsing message data:", error);
|
|
87
|
+
console.log("The underlying event:", event);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
onerror(error) {
|
|
91
|
+
setIsRequesting(false);
|
|
92
|
+
onError == null ? void 0 : onError(error);
|
|
93
|
+
},
|
|
94
|
+
onclose() {
|
|
95
|
+
setIsRequesting(false);
|
|
96
|
+
onClose == null ? void 0 : onClose();
|
|
97
|
+
},
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
...headers
|
|
101
|
+
},
|
|
102
|
+
...restOptions
|
|
103
|
+
});
|
|
104
|
+
} finally {
|
|
105
|
+
setIsRequesting(false);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
const close = (0, import_useRefFunction.default)(() => {
|
|
109
|
+
setIsConnected(false);
|
|
110
|
+
if (isConnected && abortCtrlRef.current) {
|
|
111
|
+
abortCtrlRef.current.abort();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
(0, import_react.useEffect)(() => {
|
|
115
|
+
if (autoConnectRef.current) {
|
|
116
|
+
connect();
|
|
117
|
+
}
|
|
118
|
+
return close;
|
|
119
|
+
}, []);
|
|
120
|
+
return {
|
|
121
|
+
connect,
|
|
122
|
+
close,
|
|
123
|
+
isRequesting,
|
|
124
|
+
isConnected
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
var useSSE_default = useSSE;
|
|
128
|
+
//# sourceMappingURL=useSSE.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/hooks/useSSE.ts"],
|
|
4
|
+
"sourcesContent": ["import { useEffect, useRef, useState } from 'react';\nimport type { EventSourceMessage, FetchEventSourceInit } from '@microsoft/fetch-event-source';\nimport { fetchEventSource } from '@microsoft/fetch-event-source';\nimport useRefFunction from './useRefFunction';\nimport useRefValue from './useRefValue';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface UseSSEProps<T = any> {\n /** The URL to connect to */\n url: RequestInfo;\n /** Options for the connection. */\n connectOptions?: Omit<FetchEventSourceInit, 'onmessage' | 'onerror' | 'onclose'>;\n /** Automatically connect to the SSE channel. Default is `false`. */\n autoConnect?: boolean;\n /** Automatically close the connection when the component unmounts. Default is `true`. */\n autoClose?: boolean;\n /** Function to parse the incoming message. If not provided, the default JSON parser will be used. */\n parseMessage?: (original: EventSourceMessage) => T;\n /** Callback function to handle incoming messages. */\n onMessage?: (messageData: T) => void;\n /** Callback function to handle errors. */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onError?: (error: any) => void;\n /** Callback function to handle connection closure. */\n onClose?: () => void;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst useSSE = <T = any>(props: UseSSEProps<T>) => {\n const { url, autoConnect, connectOptions, onMessage, parseMessage, onError, onClose } = props;\n const autoConnectRef = useRefValue(autoConnect);\n const [isRequesting, setIsRequesting] = useState(false);\n const isRequestingRef = useRefValue(isRequesting);\n const [isConnected, setIsConnected] = useState<boolean>(false);\n const abortCtrlRef = useRef<AbortController | undefined>(undefined);\n\n const connect = useRefFunction(async (options?: FetchEventSourceInit & Partial<Pick<UseSSEProps, 'url'>>) => {\n const {\n url: connectUrl = url,\n headers = {},\n onopen,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onmessage,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onclose,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onerror,\n ...restOptions\n } = { ...connectOptions, ...options };\n abortCtrlRef.current = new AbortController();\n try {\n setIsRequesting(true);\n setIsConnected(false);\n await fetchEventSource(connectUrl, {\n method: 'post',\n signal: abortCtrlRef.current.signal,\n openWhenHidden: true,\n onopen: async (response: Response) => {\n setIsConnected(true);\n onopen?.(response);\n },\n onmessage(event) {\n if (!isRequestingRef.current) {\n setIsRequesting(false);\n }\n try {\n let parsed: T;\n if (parseMessage) {\n parsed = parseMessage(event);\n } else {\n parsed = event.data ? JSON.parse(event.data) : undefined;\n }\n if (parsed != null) {\n onMessage?.(parsed);\n }\n } catch (error) {\n console.error('Error parsing message data:', error);\n console.log('The underlying event:', event);\n }\n },\n onerror(error) {\n setIsRequesting(false);\n onError?.(error);\n },\n onclose() {\n setIsRequesting(false);\n onClose?.();\n },\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n ...restOptions,\n });\n } finally {\n setIsRequesting(false);\n }\n });\n\n const close = useRefFunction(() => {\n setIsConnected(false);\n if (isConnected && abortCtrlRef.current) {\n abortCtrlRef.current.abort();\n }\n });\n\n useEffect(() => {\n if (autoConnectRef.current) {\n connect();\n }\n return close;\n }, []);\n\n // 清理函数\n return {\n connect,\n close,\n isRequesting,\n isConnected,\n };\n};\n\nexport default useSSE;\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4C;AAE5C,gCAAiC;AACjC,4BAA2B;AAC3B,yBAAwB;AAwBxB,IAAM,SAAS,CAAU,UAA0B;AACjD,QAAM,EAAE,KAAK,aAAa,gBAAgB,WAAW,cAAc,SAAS,QAAQ,IAAI;AACxF,QAAM,qBAAiB,mBAAAA,SAAY,WAAW;AAC9C,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AACtD,QAAM,sBAAkB,mBAAAA,SAAY,YAAY;AAChD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAkB,KAAK;AAC7D,QAAM,mBAAe,qBAAoC,MAAS;AAElE,QAAM,cAAU,sBAAAC,SAAe,OAAO,YAAuE;AAC3G,UAAM;AAAA,MACJ,KAAK,aAAa;AAAA,MAClB,UAAU,CAAC;AAAA,MACX;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA;AAAA,MAEA;AAAA,MACA,GAAG;AAAA,IACL,IAAI,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AACpC,iBAAa,UAAU,IAAI,gBAAgB;AAC3C,QAAI;AACF,sBAAgB,IAAI;AACpB,qBAAe,KAAK;AACpB,gBAAM,4CAAiB,YAAY;AAAA,QACjC,QAAQ;AAAA,QACR,QAAQ,aAAa,QAAQ;AAAA,QAC7B,gBAAgB;AAAA,QAChB,QAAQ,OAAO,aAAuB;AACpC,yBAAe,IAAI;AACnB,2CAAS;AAAA,QACX;AAAA,QACA,UAAU,OAAO;AACf,cAAI,CAAC,gBAAgB,SAAS;AAC5B,4BAAgB,KAAK;AAAA,UACvB;AACA,cAAI;AACF,gBAAI;AACJ,gBAAI,cAAc;AAChB,uBAAS,aAAa,KAAK;AAAA,YAC7B,OAAO;AACL,uBAAS,MAAM,OAAO,KAAK,MAAM,MAAM,IAAI,IAAI;AAAA,YACjD;AACA,gBAAI,UAAU,MAAM;AAClB,qDAAY;AAAA,YACd;AAAA,UACF,SAAS,OAAP;AACA,oBAAQ,MAAM,+BAA+B,KAAK;AAClD,oBAAQ,IAAI,yBAAyB,KAAK;AAAA,UAC5C;AAAA,QACF;AAAA,QACA,QAAQ,OAAO;AACb,0BAAgB,KAAK;AACrB,6CAAU;AAAA,QACZ;AAAA,QACA,UAAU;AACR,0BAAgB,KAAK;AACrB;AAAA,QACF;AAAA,QACA,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,GAAG;AAAA,QACL;AAAA,QACA,GAAG;AAAA,MACL,CAAC;AAAA,IACH,UAAE;AACA,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,CAAC;AAED,QAAM,YAAQ,sBAAAA,SAAe,MAAM;AACjC,mBAAe,KAAK;AACpB,QAAI,eAAe,aAAa,SAAS;AACvC,mBAAa,QAAQ,MAAM;AAAA,IAC7B;AAAA,EACF,CAAC;AAED,8BAAU,MAAM;AACd,QAAI,eAAe,SAAS;AAC1B,cAAQ;AAAA,IACV;AACA,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAGL,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,IAAO,iBAAQ;",
|
|
6
|
+
"names": ["useRefValue", "useRefFunction"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
export type AudioSource = string | ReadableStreamDefaultReader<Uint8Array>;
|
|
2
|
+
export interface AudioPlayerInit {
|
|
3
|
+
/**
|
|
4
|
+
* - **EN:** Audio source (URL or streaming data)
|
|
5
|
+
* - **CN:** 音频源(URL或流数据)
|
|
6
|
+
*/
|
|
7
|
+
source?: AudioSource | (() => AudioSource | Promise<AudioSource>);
|
|
8
|
+
/**
|
|
9
|
+
* - **EN:** Initial volume level (0-1). Default is `0.5`
|
|
10
|
+
* - **CN:** 初始音量级别(0-1)。默认值为`0.5`
|
|
11
|
+
*/
|
|
12
|
+
volume?: number;
|
|
13
|
+
/**
|
|
14
|
+
* - **EN:** Callback when audio starts playing
|
|
15
|
+
* - **CN:** 音频开始播放时的回调
|
|
16
|
+
*/
|
|
17
|
+
onPlay?: () => void;
|
|
18
|
+
/**
|
|
19
|
+
* - **EN:** Callback when audio is paused
|
|
20
|
+
* - **CN:** 音频暂停时的回调
|
|
21
|
+
*/
|
|
22
|
+
onPause?: () => void;
|
|
23
|
+
/**
|
|
24
|
+
* - **EN:** Callback when audio is stopped
|
|
25
|
+
* - **CN:** 音频停止时的回调
|
|
26
|
+
*/
|
|
27
|
+
onStop?: () => void;
|
|
28
|
+
/**
|
|
29
|
+
* - **EN:** Callback when audio playback ends
|
|
30
|
+
* - **CN:** 音频播放结束时的回调
|
|
31
|
+
*/
|
|
32
|
+
onPlayEnd?: () => void;
|
|
33
|
+
/**
|
|
34
|
+
* - **EN:** Callback when an error occurs
|
|
35
|
+
* - **CN:** 发生错误时的回调
|
|
36
|
+
*/
|
|
37
|
+
onError?: (error: any) => void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* - **EN:** An audio player class that supports URL or streaming data input
|
|
41
|
+
* - **CN:** 一个音频播放器类,支持URL或流数据输入
|
|
42
|
+
*/
|
|
43
|
+
declare class AudioPlayer {
|
|
44
|
+
private audio;
|
|
45
|
+
private volume;
|
|
46
|
+
private audioContext;
|
|
47
|
+
private gainNode;
|
|
48
|
+
private sourceNode;
|
|
49
|
+
private options;
|
|
50
|
+
private onPlayEnd;
|
|
51
|
+
/**
|
|
52
|
+
* - **EN:** Creates an audio player instance
|
|
53
|
+
* - **CN:** 创建音频播放器实例
|
|
54
|
+
*
|
|
55
|
+
* @param source - can be a URL string or ReadableStreamDefaultReader |
|
|
56
|
+
* 可以是URL字符串或ReadableStreamDefaultReader
|
|
57
|
+
*/
|
|
58
|
+
constructor(options?: AudioPlayerInit);
|
|
59
|
+
/**
|
|
60
|
+
* - **EN:** Check if audio is currently playing
|
|
61
|
+
* - **CN:** 检查音频是否正在播放
|
|
62
|
+
*/
|
|
63
|
+
get isPlaying(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* - **EN:** Play audio. If previously paused, will resume from the pause position
|
|
66
|
+
* - **CN:** 播放音频 如果之前暂停过,将从暂停位置继续播放
|
|
67
|
+
*/
|
|
68
|
+
play(): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* - **EN:** Set current playback time (in seconds)
|
|
71
|
+
* - **CN:** 设置当前播放时间(以秒为单位)
|
|
72
|
+
*
|
|
73
|
+
* @param time - time in seconds | 时间(秒)
|
|
74
|
+
*/
|
|
75
|
+
gotoTime(time: number): void;
|
|
76
|
+
/**
|
|
77
|
+
* - **EN:** Set playback position by percentage
|
|
78
|
+
* - **CN:** 按百分比设置播放位置
|
|
79
|
+
*
|
|
80
|
+
* @param percent - percentage (0-1) | 百分比(0-1)
|
|
81
|
+
*/
|
|
82
|
+
gotoPercent(percent: number): void;
|
|
83
|
+
/**
|
|
84
|
+
* - **EN:** Pause audio playback. When played again, will continue from current position
|
|
85
|
+
* - **CN:** 暂停音频播放 再次播放时将从当前位置继续
|
|
86
|
+
*/
|
|
87
|
+
pause(): void;
|
|
88
|
+
/**
|
|
89
|
+
* - **EN:** Stop audio playback. Progress will reset to the beginning
|
|
90
|
+
* - **CN:** 停止音频播放 进度会重置到开始位置
|
|
91
|
+
*/
|
|
92
|
+
stop(): void;
|
|
93
|
+
/**
|
|
94
|
+
* - **EN:** Update audio source
|
|
95
|
+
* - **CN:** 更新音频源
|
|
96
|
+
*
|
|
97
|
+
* @param source - can be a URL `string` or `ReadableStreamDefaultReader` |
|
|
98
|
+
* 可以是URL字符串或`ReadableStreamDefaultReader`
|
|
99
|
+
*/
|
|
100
|
+
setAudioSource(source?: AudioSource): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* - **EN:** Increase volume (by 10% each time)
|
|
103
|
+
* - **CN:** 增加音量(每次增加10%)
|
|
104
|
+
*
|
|
105
|
+
* @param percent - increase percentage (default 10%) | 增加百分比(默认10%)
|
|
106
|
+
*/
|
|
107
|
+
volumeUp(percent?: number): void;
|
|
108
|
+
/**
|
|
109
|
+
* - **EN:** Decrease volume (by 10% each time)
|
|
110
|
+
* - **CN:** 降低音量(每次降低10%)
|
|
111
|
+
*
|
|
112
|
+
* @param percent - decrease percentage (default 10%) | 降低百分比(默认10%)
|
|
113
|
+
*/
|
|
114
|
+
volumeDown(percent?: number): void;
|
|
115
|
+
/**
|
|
116
|
+
* - **EN:** Set volume to a specific value (0-1)
|
|
117
|
+
* - **CN:** 将音量设置为特定值(0-1)
|
|
118
|
+
*
|
|
119
|
+
* @param value - new volume value (0-1) | 新的音量值(0-1)
|
|
120
|
+
*/
|
|
121
|
+
setVolume(value: number): void;
|
|
122
|
+
/**
|
|
123
|
+
* - **EN:** Get current volume value (0-1)
|
|
124
|
+
* - **CN:** 获取当前音量值(0-1)
|
|
125
|
+
*/
|
|
126
|
+
getVolume(): number;
|
|
127
|
+
/**
|
|
128
|
+
* - **EN:** Get current playback time (seconds)
|
|
129
|
+
* - **CN:** 获取当前播放时间(秒)
|
|
130
|
+
*/
|
|
131
|
+
getCurrentTime(): number;
|
|
132
|
+
/**
|
|
133
|
+
* - **EN:** Get total audio duration (seconds)
|
|
134
|
+
* - **CN:** 获取音频总时长(秒)
|
|
135
|
+
*/
|
|
136
|
+
getDuration(): number;
|
|
137
|
+
/**
|
|
138
|
+
* - **EN:** Add audio event listener
|
|
139
|
+
* - **CN:** 添加音频事件监听器
|
|
140
|
+
*/
|
|
141
|
+
addEventListener: HTMLAudioElement['addEventListener'];
|
|
142
|
+
/**
|
|
143
|
+
* - **EN:** Remove audio event listener
|
|
144
|
+
* - **CN:** 移除音频事件监听器
|
|
145
|
+
*/
|
|
146
|
+
removeEventListener: HTMLAudioElement['removeEventListener'];
|
|
147
|
+
/**
|
|
148
|
+
* - **EN:** Release resources
|
|
149
|
+
* - **CN:** 释放资源
|
|
150
|
+
*/
|
|
151
|
+
dispose(): void;
|
|
152
|
+
/** Process streaming data source */
|
|
153
|
+
private handleStreamSource;
|
|
154
|
+
/** Initialize Web Audio API for better volume control */
|
|
155
|
+
private initAudioContext;
|
|
156
|
+
/** Update audio playback volume */
|
|
157
|
+
private updateVolume;
|
|
158
|
+
}
|
|
159
|
+
export default AudioPlayer;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/utils/AudioPlayer.ts
|
|
20
|
+
var AudioPlayer_exports = {};
|
|
21
|
+
__export(AudioPlayer_exports, {
|
|
22
|
+
default: () => AudioPlayer_default
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(AudioPlayer_exports);
|
|
25
|
+
var AudioPlayer = class {
|
|
26
|
+
/**
|
|
27
|
+
* - **EN:** Creates an audio player instance
|
|
28
|
+
* - **CN:** 创建音频播放器实例
|
|
29
|
+
*
|
|
30
|
+
* @param source - can be a URL string or ReadableStreamDefaultReader |
|
|
31
|
+
* 可以是URL字符串或ReadableStreamDefaultReader
|
|
32
|
+
*/
|
|
33
|
+
constructor(options) {
|
|
34
|
+
this.audioContext = null;
|
|
35
|
+
this.gainNode = null;
|
|
36
|
+
this.sourceNode = null;
|
|
37
|
+
/**
|
|
38
|
+
* - **EN:** Add audio event listener
|
|
39
|
+
* - **CN:** 添加音频事件监听器
|
|
40
|
+
*/
|
|
41
|
+
this.addEventListener = (event, listener) => {
|
|
42
|
+
this.audio.addEventListener(event, listener);
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* - **EN:** Remove audio event listener
|
|
46
|
+
* - **CN:** 移除音频事件监听器
|
|
47
|
+
*/
|
|
48
|
+
this.removeEventListener = (event, listener) => {
|
|
49
|
+
this.audio.removeEventListener(event, listener);
|
|
50
|
+
};
|
|
51
|
+
const { source, volume } = options || {};
|
|
52
|
+
this.options = options;
|
|
53
|
+
this.audio = new Audio();
|
|
54
|
+
this.volume = volume != null ? Math.min(1, Math.max(0, volume)) : 0.5;
|
|
55
|
+
this.audio.volume = this.volume;
|
|
56
|
+
if (typeof source === "function") {
|
|
57
|
+
const result = source();
|
|
58
|
+
if (typeof result === "object" && "then" in result && typeof result.then === "function") {
|
|
59
|
+
result.then((data) => this.setAudioSource(data));
|
|
60
|
+
} else {
|
|
61
|
+
this.setAudioSource(result);
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
this.setAudioSource(source);
|
|
65
|
+
}
|
|
66
|
+
this.onPlayEnd = () => {
|
|
67
|
+
var _a, _b;
|
|
68
|
+
(_b = (_a = this.options) == null ? void 0 : _a.onPlayEnd) == null ? void 0 : _b.call(_a);
|
|
69
|
+
};
|
|
70
|
+
this.addEventListener("ended", this.onPlayEnd);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* - **EN:** Check if audio is currently playing
|
|
74
|
+
* - **CN:** 检查音频是否正在播放
|
|
75
|
+
*/
|
|
76
|
+
get isPlaying() {
|
|
77
|
+
var _a;
|
|
78
|
+
return ((_a = this.audioContext) == null ? void 0 : _a.state) === "running";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* - **EN:** Play audio. If previously paused, will resume from the pause position
|
|
82
|
+
* - **CN:** 播放音频 如果之前暂停过,将从暂停位置继续播放
|
|
83
|
+
*/
|
|
84
|
+
async play() {
|
|
85
|
+
var _a, _b, _c, _d, _e;
|
|
86
|
+
if (!this.audioContext) {
|
|
87
|
+
this.initAudioContext();
|
|
88
|
+
}
|
|
89
|
+
if (((_a = this.audioContext) == null ? void 0 : _a.state) === "suspended") {
|
|
90
|
+
await this.audioContext.resume();
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
await this.audio.play();
|
|
94
|
+
(_c = (_b = this.options) == null ? void 0 : _b.onPlay) == null ? void 0 : _c.call(_b);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error("Error playing audio:", error);
|
|
97
|
+
(_e = (_d = this.options) == null ? void 0 : _d.onError) == null ? void 0 : _e.call(_d, error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* - **EN:** Set current playback time (in seconds)
|
|
102
|
+
* - **CN:** 设置当前播放时间(以秒为单位)
|
|
103
|
+
*
|
|
104
|
+
* @param time - time in seconds | 时间(秒)
|
|
105
|
+
*/
|
|
106
|
+
gotoTime(time) {
|
|
107
|
+
const newTime = Math.max(0, time);
|
|
108
|
+
if (!isNaN(this.audio.duration)) {
|
|
109
|
+
this.audio.currentTime = Math.min(newTime, this.audio.duration);
|
|
110
|
+
} else {
|
|
111
|
+
this.audio.currentTime = newTime;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* - **EN:** Set playback position by percentage
|
|
116
|
+
* - **CN:** 按百分比设置播放位置
|
|
117
|
+
*
|
|
118
|
+
* @param percent - percentage (0-1) | 百分比(0-1)
|
|
119
|
+
*/
|
|
120
|
+
gotoPercent(percent) {
|
|
121
|
+
if (isNaN(this.audio.duration)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const clampedPercent = Math.min(1, Math.max(0, percent));
|
|
125
|
+
const newTime = this.audio.duration * clampedPercent;
|
|
126
|
+
this.audio.currentTime = newTime;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* - **EN:** Pause audio playback. When played again, will continue from current position
|
|
130
|
+
* - **CN:** 暂停音频播放 再次播放时将从当前位置继续
|
|
131
|
+
*/
|
|
132
|
+
pause() {
|
|
133
|
+
var _a, _b;
|
|
134
|
+
this.audio.pause();
|
|
135
|
+
(_b = (_a = this.options) == null ? void 0 : _a.onPause) == null ? void 0 : _b.call(_a);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* - **EN:** Stop audio playback. Progress will reset to the beginning
|
|
139
|
+
* - **CN:** 停止音频播放 进度会重置到开始位置
|
|
140
|
+
*/
|
|
141
|
+
stop() {
|
|
142
|
+
var _a, _b;
|
|
143
|
+
this.audio.pause();
|
|
144
|
+
this.audio.currentTime = 0;
|
|
145
|
+
(_b = (_a = this.options) == null ? void 0 : _a.onStop) == null ? void 0 : _b.call(_a);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* - **EN:** Update audio source
|
|
149
|
+
* - **CN:** 更新音频源
|
|
150
|
+
*
|
|
151
|
+
* @param source - can be a URL `string` or `ReadableStreamDefaultReader` |
|
|
152
|
+
* 可以是URL字符串或`ReadableStreamDefaultReader`
|
|
153
|
+
*/
|
|
154
|
+
async setAudioSource(source) {
|
|
155
|
+
this.audio.pause();
|
|
156
|
+
this.audio.src = "";
|
|
157
|
+
if (typeof source === "string") {
|
|
158
|
+
this.audio.src = source;
|
|
159
|
+
} else {
|
|
160
|
+
await this.handleStreamSource(source);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* - **EN:** Increase volume (by 10% each time)
|
|
165
|
+
* - **CN:** 增加音量(每次增加10%)
|
|
166
|
+
*
|
|
167
|
+
* @param percent - increase percentage (default 10%) | 增加百分比(默认10%)
|
|
168
|
+
*/
|
|
169
|
+
volumeUp(percent = 0.1) {
|
|
170
|
+
this.volume = Math.min(1, this.volume + percent);
|
|
171
|
+
this.updateVolume();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* - **EN:** Decrease volume (by 10% each time)
|
|
175
|
+
* - **CN:** 降低音量(每次降低10%)
|
|
176
|
+
*
|
|
177
|
+
* @param percent - decrease percentage (default 10%) | 降低百分比(默认10%)
|
|
178
|
+
*/
|
|
179
|
+
volumeDown(percent = 0.1) {
|
|
180
|
+
this.volume = Math.max(0, this.volume - percent);
|
|
181
|
+
this.updateVolume();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* - **EN:** Set volume to a specific value (0-1)
|
|
185
|
+
* - **CN:** 将音量设置为特定值(0-1)
|
|
186
|
+
*
|
|
187
|
+
* @param value - new volume value (0-1) | 新的音量值(0-1)
|
|
188
|
+
*/
|
|
189
|
+
setVolume(value) {
|
|
190
|
+
this.volume = Math.min(1, Math.max(0, value));
|
|
191
|
+
this.updateVolume();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* - **EN:** Get current volume value (0-1)
|
|
195
|
+
* - **CN:** 获取当前音量值(0-1)
|
|
196
|
+
*/
|
|
197
|
+
getVolume() {
|
|
198
|
+
return this.volume;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* - **EN:** Get current playback time (seconds)
|
|
202
|
+
* - **CN:** 获取当前播放时间(秒)
|
|
203
|
+
*/
|
|
204
|
+
getCurrentTime() {
|
|
205
|
+
return this.audio.currentTime;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* - **EN:** Get total audio duration (seconds)
|
|
209
|
+
* - **CN:** 获取音频总时长(秒)
|
|
210
|
+
*/
|
|
211
|
+
getDuration() {
|
|
212
|
+
return this.audio.duration;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* - **EN:** Release resources
|
|
216
|
+
* - **CN:** 释放资源
|
|
217
|
+
*/
|
|
218
|
+
dispose() {
|
|
219
|
+
this.audio.pause();
|
|
220
|
+
this.audio.src = "";
|
|
221
|
+
this.removeEventListener("ended", this.onPlayEnd);
|
|
222
|
+
if (this.audioContext) {
|
|
223
|
+
try {
|
|
224
|
+
this.audioContext.close();
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error("Error closing AudioContext:", error);
|
|
227
|
+
}
|
|
228
|
+
this.audioContext = null;
|
|
229
|
+
}
|
|
230
|
+
this.sourceNode = null;
|
|
231
|
+
this.gainNode = null;
|
|
232
|
+
}
|
|
233
|
+
/** Process streaming data source */
|
|
234
|
+
async handleStreamSource(reader) {
|
|
235
|
+
if (!reader)
|
|
236
|
+
return;
|
|
237
|
+
try {
|
|
238
|
+
const stream = new ReadableStream({
|
|
239
|
+
async pull(controller) {
|
|
240
|
+
try {
|
|
241
|
+
const { done, value } = await reader.read();
|
|
242
|
+
if (done) {
|
|
243
|
+
controller.close();
|
|
244
|
+
} else {
|
|
245
|
+
controller.enqueue(value);
|
|
246
|
+
}
|
|
247
|
+
} catch (err) {
|
|
248
|
+
controller.error(err);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
const response = new Response(stream);
|
|
253
|
+
const blob = await response.blob();
|
|
254
|
+
const url = URL.createObjectURL(blob);
|
|
255
|
+
this.audio.src = url;
|
|
256
|
+
this.audio.onload = () => {
|
|
257
|
+
URL.revokeObjectURL(url);
|
|
258
|
+
};
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error("Error processing audio stream:", error);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/** Initialize Web Audio API for better volume control */
|
|
264
|
+
initAudioContext() {
|
|
265
|
+
if (this.audioContext)
|
|
266
|
+
return;
|
|
267
|
+
this.audioContext = new AudioContext();
|
|
268
|
+
this.sourceNode = this.audioContext.createMediaElementSource(this.audio);
|
|
269
|
+
this.gainNode = this.audioContext.createGain();
|
|
270
|
+
this.sourceNode.connect(this.gainNode);
|
|
271
|
+
this.gainNode.connect(this.audioContext.destination);
|
|
272
|
+
this.gainNode.gain.value = this.volume;
|
|
273
|
+
}
|
|
274
|
+
/** Update audio playback volume */
|
|
275
|
+
updateVolume() {
|
|
276
|
+
if (this.gainNode) {
|
|
277
|
+
this.gainNode.gain.value = this.volume;
|
|
278
|
+
} else {
|
|
279
|
+
this.audio.volume = this.volume;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
var AudioPlayer_default = AudioPlayer;
|
|
284
|
+
//# sourceMappingURL=AudioPlayer.js.map
|