audio-channel-queue 1.6.0 → 1.7.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.
- package/dist/core.js +53 -34
- package/dist/errors.d.ts +137 -0
- package/dist/errors.js +461 -0
- package/dist/index.d.ts +9 -25
- package/dist/index.js +23 -33
- package/dist/info.d.ts +2 -1
- package/dist/info.js +8 -1
- package/dist/pause.js +1 -1
- package/dist/types.d.ts +52 -19
- package/dist/volume.js +4 -1
- package/package.json +1 -1
- package/src/core.ts +55 -35
- package/src/errors.ts +480 -0
- package/src/index.ts +71 -84
- package/src/info.ts +8 -1
- package/src/pause.ts +189 -189
- package/src/types.ts +55 -18
- package/src/volume.ts +330 -327
package/dist/core.js
CHANGED
|
@@ -17,6 +17,7 @@ const info_1 = require("./info");
|
|
|
17
17
|
const utils_1 = require("./utils");
|
|
18
18
|
const events_1 = require("./events");
|
|
19
19
|
const volume_1 = require("./volume");
|
|
20
|
+
const errors_1 = require("./errors");
|
|
20
21
|
/**
|
|
21
22
|
* Queues an audio file to a specific channel and starts playing if it's the first in queue
|
|
22
23
|
* @param audioUrl - The URL of the audio file to queue
|
|
@@ -32,9 +33,11 @@ const volume_1 = require("./volume");
|
|
|
32
33
|
* ```
|
|
33
34
|
*/
|
|
34
35
|
const queueAudio = (audioUrl_1, ...args_1) => __awaiter(void 0, [audioUrl_1, ...args_1], void 0, function* (audioUrl, channelNumber = 0, options) {
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
// Ensure the channel exists
|
|
37
|
+
while (info_1.audioChannels.length <= channelNumber) {
|
|
38
|
+
info_1.audioChannels.push({
|
|
37
39
|
audioCompleteCallbacks: new Set(),
|
|
40
|
+
audioErrorCallbacks: new Set(),
|
|
38
41
|
audioPauseCallbacks: new Set(),
|
|
39
42
|
audioResumeCallbacks: new Set(),
|
|
40
43
|
audioStartCallbacks: new Set(),
|
|
@@ -43,43 +46,51 @@ const queueAudio = (audioUrl_1, ...args_1) => __awaiter(void 0, [audioUrl_1, ...
|
|
|
43
46
|
queue: [],
|
|
44
47
|
queueChangeCallbacks: new Set(),
|
|
45
48
|
volume: 1.0
|
|
46
|
-
};
|
|
49
|
+
});
|
|
47
50
|
}
|
|
51
|
+
const channel = info_1.audioChannels[channelNumber];
|
|
48
52
|
const audio = new Audio(audioUrl);
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
audio
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
audio.volume = channelVolume;
|
|
53
|
+
// Set up comprehensive error handling
|
|
54
|
+
(0, errors_1.setupAudioErrorHandling)(audio, channelNumber, audioUrl, (error) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
yield (0, errors_1.handleAudioError)(audio, channelNumber, audioUrl, error);
|
|
56
|
+
}));
|
|
57
|
+
// Apply options if provided
|
|
58
|
+
if (options) {
|
|
59
|
+
if (typeof options.loop === 'boolean') {
|
|
60
|
+
audio.loop = options.loop;
|
|
61
|
+
}
|
|
62
|
+
if (typeof options.volume === 'number' && !isNaN(options.volume)) {
|
|
63
|
+
const clampedVolume = Math.max(0, Math.min(1, options.volume));
|
|
64
|
+
audio.volume = clampedVolume;
|
|
65
|
+
// Set channel volume to match the audio volume
|
|
66
|
+
channel.volume = clampedVolume;
|
|
67
|
+
}
|
|
65
68
|
}
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
// Handle priority option (same as addToFront for backward compatibility)
|
|
70
|
+
const shouldAddToFront = (options === null || options === void 0 ? void 0 : options.addToFront) || (options === null || options === void 0 ? void 0 : options.priority);
|
|
71
|
+
// Add to queue based on priority/addToFront option
|
|
72
|
+
if (shouldAddToFront && channel.queue.length > 0) {
|
|
73
|
+
// Insert after currently playing track (at index 1)
|
|
74
|
+
channel.queue.splice(1, 0, audio);
|
|
70
75
|
}
|
|
71
|
-
else if (
|
|
72
|
-
// If queue is empty,
|
|
73
|
-
|
|
76
|
+
else if (shouldAddToFront) {
|
|
77
|
+
// If queue is empty, add to front
|
|
78
|
+
channel.queue.unshift(audio);
|
|
74
79
|
}
|
|
75
80
|
else {
|
|
76
|
-
//
|
|
77
|
-
|
|
81
|
+
// Add to back of queue
|
|
82
|
+
channel.queue.push(audio);
|
|
78
83
|
}
|
|
84
|
+
// Emit queue change event
|
|
79
85
|
(0, events_1.emitQueueChange)(channelNumber, info_1.audioChannels);
|
|
80
|
-
if
|
|
81
|
-
|
|
82
|
-
|
|
86
|
+
// Start playing if this is the first item and channel isn't paused
|
|
87
|
+
if (channel.queue.length === 1 && !channel.isPaused) {
|
|
88
|
+
// Use setTimeout to ensure the queue change event is emitted first
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
(0, exports.playAudioQueue)(channelNumber).catch((error) => {
|
|
91
|
+
(0, errors_1.handleAudioError)(audio, channelNumber, audioUrl, error);
|
|
92
|
+
});
|
|
93
|
+
}, 0);
|
|
83
94
|
}
|
|
84
95
|
});
|
|
85
96
|
exports.queueAudio = queueAudio;
|
|
@@ -167,8 +178,12 @@ const playAudioQueue = (channelNumber) => __awaiter(void 0, void 0, void 0, func
|
|
|
167
178
|
if (currentAudio.loop) {
|
|
168
179
|
// For looping audio, reset current time and continue playing
|
|
169
180
|
currentAudio.currentTime = 0;
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
try {
|
|
182
|
+
yield currentAudio.play();
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
yield (0, errors_1.handleAudioError)(currentAudio, channelNumber, currentAudio.src, error);
|
|
186
|
+
}
|
|
172
187
|
resolve();
|
|
173
188
|
}
|
|
174
189
|
else {
|
|
@@ -188,7 +203,11 @@ const playAudioQueue = (channelNumber) => __awaiter(void 0, void 0, void 0, func
|
|
|
188
203
|
if (currentAudio.readyState >= 1) { // HAVE_METADATA or higher
|
|
189
204
|
metadataLoaded = true;
|
|
190
205
|
}
|
|
191
|
-
|
|
206
|
+
// Enhanced play with error handling
|
|
207
|
+
currentAudio.play().catch((error) => __awaiter(void 0, void 0, void 0, function* () {
|
|
208
|
+
yield (0, errors_1.handleAudioError)(currentAudio, channelNumber, currentAudio.src, error);
|
|
209
|
+
resolve(); // Resolve to prevent hanging
|
|
210
|
+
}));
|
|
192
211
|
});
|
|
193
212
|
});
|
|
194
213
|
exports.playAudioQueue = playAudioQueue;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Error handling, retry logic, and recovery mechanisms for the audio-channel-queue package
|
|
3
|
+
*/
|
|
4
|
+
import { AudioErrorInfo, AudioErrorCallback, RetryConfig, ErrorRecoveryOptions, ExtendedAudioQueueChannel } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Subscribes to audio error events for a specific channel
|
|
7
|
+
* @param channelNumber - The channel number to listen to (defaults to 0)
|
|
8
|
+
* @param callback - Function to call when an audio error occurs
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* onAudioError(0, (errorInfo) => {
|
|
12
|
+
* console.log(`Audio error: ${errorInfo.error.message}`);
|
|
13
|
+
* console.log(`Error type: ${errorInfo.errorType}`);
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare const onAudioError: (channelNumber: number | undefined, callback: AudioErrorCallback) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Unsubscribes from audio error events for a specific channel
|
|
20
|
+
* @param channelNumber - The channel number to stop listening to (defaults to 0)
|
|
21
|
+
* @param callback - The specific callback to remove (optional - if not provided, removes all)
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* offAudioError(0); // Remove all error callbacks for channel 0
|
|
25
|
+
* offAudioError(0, specificCallback); // Remove specific callback
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare const offAudioError: (channelNumber?: number, callback?: AudioErrorCallback) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Sets the global retry configuration for audio loading failures
|
|
31
|
+
* @param config - Retry configuration options
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* setRetryConfig({
|
|
35
|
+
* enabled: true,
|
|
36
|
+
* maxRetries: 5,
|
|
37
|
+
* baseDelay: 1000,
|
|
38
|
+
* exponentialBackoff: true,
|
|
39
|
+
* timeoutMs: 15000,
|
|
40
|
+
* fallbackUrls: ['https://cdn.backup.com/audio/'],
|
|
41
|
+
* skipOnFailure: true
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare const setRetryConfig: (config: Partial<RetryConfig>) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Gets the current global retry configuration
|
|
48
|
+
* @returns Current retry configuration
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const config = getRetryConfig();
|
|
52
|
+
* console.log(`Max retries: ${config.maxRetries}`);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare const getRetryConfig: () => RetryConfig;
|
|
56
|
+
/**
|
|
57
|
+
* Sets the global error recovery configuration
|
|
58
|
+
* @param options - Error recovery options
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* setErrorRecovery({
|
|
62
|
+
* autoRetry: true,
|
|
63
|
+
* showUserFeedback: true,
|
|
64
|
+
* logErrorsToAnalytics: true,
|
|
65
|
+
* preserveQueueOnError: true,
|
|
66
|
+
* fallbackToNextTrack: true
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare const setErrorRecovery: (options: Partial<ErrorRecoveryOptions>) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Gets the current global error recovery configuration
|
|
73
|
+
* @returns Current error recovery configuration
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const recovery = getErrorRecovery();
|
|
77
|
+
* console.log(`Auto retry enabled: ${recovery.autoRetry}`);
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare const getErrorRecovery: () => ErrorRecoveryOptions;
|
|
81
|
+
/**
|
|
82
|
+
* Manually retries loading failed audio for a specific channel
|
|
83
|
+
* @param channelNumber - The channel number to retry (defaults to 0)
|
|
84
|
+
* @returns Promise that resolves to true if retry was successful, false otherwise
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const success = await retryFailedAudio(0);
|
|
88
|
+
* if (success) {
|
|
89
|
+
* console.log('Audio retry successful');
|
|
90
|
+
* } else {
|
|
91
|
+
* console.log('Audio retry failed');
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare const retryFailedAudio: (channelNumber?: number) => Promise<boolean>;
|
|
96
|
+
/**
|
|
97
|
+
* Emits an audio error event to all registered listeners for a specific channel
|
|
98
|
+
* @param channelNumber - The channel number where the error occurred
|
|
99
|
+
* @param errorInfo - Information about the error
|
|
100
|
+
* @param audioChannels - Array of audio channels
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
export declare const emitAudioError: (channelNumber: number, errorInfo: AudioErrorInfo, audioChannels: ExtendedAudioQueueChannel[]) => void;
|
|
104
|
+
/**
|
|
105
|
+
* Determines the error type based on the error object and context
|
|
106
|
+
* @param error - The error that occurred
|
|
107
|
+
* @param audio - The audio element that failed
|
|
108
|
+
* @returns The categorized error type
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
export declare const categorizeError: (error: Error, audio: HTMLAudioElement) => AudioErrorInfo["errorType"];
|
|
112
|
+
/**
|
|
113
|
+
* Sets up comprehensive error handling for an audio element
|
|
114
|
+
* @param audio - The audio element to set up error handling for
|
|
115
|
+
* @param channelNumber - The channel number this audio belongs to
|
|
116
|
+
* @param originalUrl - The original URL that was requested
|
|
117
|
+
* @param onError - Callback for when an error occurs
|
|
118
|
+
* @internal
|
|
119
|
+
*/
|
|
120
|
+
export declare const setupAudioErrorHandling: (audio: HTMLAudioElement, channelNumber: number, originalUrl: string, onError?: (error: Error) => Promise<void>) => void;
|
|
121
|
+
/**
|
|
122
|
+
* Handles audio errors with retry logic and recovery mechanisms
|
|
123
|
+
* @param audio - The audio element that failed
|
|
124
|
+
* @param channelNumber - The channel number
|
|
125
|
+
* @param originalUrl - The original URL that was requested
|
|
126
|
+
* @param error - The error that occurred
|
|
127
|
+
* @internal
|
|
128
|
+
*/
|
|
129
|
+
export declare const handleAudioError: (audio: HTMLAudioElement, channelNumber: number, originalUrl: string, error: Error) => Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Creates a timeout-protected audio element with comprehensive error handling
|
|
132
|
+
* @param url - The audio URL to load
|
|
133
|
+
* @param channelNumber - The channel number this audio belongs to
|
|
134
|
+
* @returns Promise that resolves to the configured audio element
|
|
135
|
+
* @internal
|
|
136
|
+
*/
|
|
137
|
+
export declare const createProtectedAudioElement: (url: string, channelNumber: number) => Promise<HTMLAudioElement>;
|