@students-dev/audify-js 1.0.0 → 1.0.2
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/LICENSE +21 -0
- package/README.md +93 -310
- package/dist/AudioEngine.js +232 -0
- package/dist/cjs/index.js +1497 -1392
- package/dist/cjs/index.js.map +1 -1
- package/dist/constants/index.js +35 -0
- package/dist/engine/Filters.js +137 -0
- package/dist/engine/MockAudioContext.js +53 -0
- package/dist/engine/Player.js +209 -0
- package/dist/esm/index.js +1490 -1389
- package/dist/esm/index.js.map +1 -1
- package/dist/events/EventBus.js +61 -0
- package/dist/index.js +18 -0
- package/dist/interfaces/index.js +1 -0
- package/dist/plugins/Plugin.js +27 -0
- package/dist/plugins/PluginManager.js +106 -0
- package/dist/providers/LavalinkProvider.js +81 -0
- package/dist/providers/LocalProvider.js +70 -0
- package/dist/providers/ProviderRegistry.js +20 -0
- package/dist/providers/SpotifyProvider.js +59 -0
- package/dist/providers/YouTubeProvider.js +48 -0
- package/dist/queue/Queue.js +186 -0
- package/dist/queue/Track.js +54 -0
- package/dist/types/AudioEngine.d.ts +107 -0
- package/dist/types/constants/index.d.ts +39 -0
- package/dist/types/engine/AudioEngine.d.ts +44 -1
- package/dist/types/engine/Filters.d.ts +25 -24
- package/dist/types/engine/MockAudioContext.d.ts +43 -0
- package/dist/types/engine/Player.d.ts +25 -21
- package/dist/types/events/EventBus.d.ts +17 -15
- package/dist/types/index.d.ts +17 -13
- package/dist/types/interfaces/index.d.ts +31 -0
- package/dist/types/plugins/Plugin.d.ts +11 -43
- package/dist/types/plugins/PluginManager.d.ts +19 -19
- package/dist/types/providers/LavalinkProvider.d.ts +17 -0
- package/dist/types/providers/LocalProvider.d.ts +11 -22
- package/dist/types/providers/ProviderRegistry.d.ts +10 -0
- package/dist/types/providers/SpotifyProvider.d.ts +14 -0
- package/dist/types/providers/YouTubeProvider.d.ts +11 -28
- package/dist/types/queue/Queue.d.ts +28 -22
- package/dist/types/queue/Track.d.ts +18 -16
- package/dist/types/utils/Logger.d.ts +12 -16
- package/dist/types/utils/Metadata.d.ts +16 -15
- package/dist/types/utils/Probe.d.ts +7 -7
- package/dist/types/utils/Time.d.ts +9 -9
- package/dist/utils/Logger.js +59 -0
- package/dist/utils/Metadata.js +90 -0
- package/dist/utils/Probe.js +59 -0
- package/dist/utils/Time.js +54 -0
- package/package.json +19 -9
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
import { Track } from './Track';
|
|
2
|
+
import { EventBus } from '../events/EventBus';
|
|
3
|
+
import { ITrack } from '../interfaces';
|
|
1
4
|
/**
|
|
2
5
|
* Audio queue management
|
|
3
6
|
*/
|
|
4
|
-
export class Queue {
|
|
5
|
-
tracks
|
|
6
|
-
currentIndex
|
|
7
|
+
export declare class Queue {
|
|
8
|
+
private tracks;
|
|
9
|
+
private currentIndex;
|
|
7
10
|
eventBus: EventBus;
|
|
11
|
+
constructor();
|
|
8
12
|
/**
|
|
9
13
|
* Add track(s) to queue
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
14
|
+
* @param tracks - Track(s) to add
|
|
15
|
+
* @param position - Position to insert (optional)
|
|
12
16
|
*/
|
|
13
|
-
add(tracks: Track | Track[] | string | string[], position
|
|
17
|
+
add(tracks: Track | ITrack | (Track | ITrack)[] | string | string[], position?: number): void;
|
|
14
18
|
/**
|
|
15
19
|
* Remove track from queue
|
|
16
|
-
* @param
|
|
17
|
-
* @returns
|
|
20
|
+
* @param identifier - Track index or ID
|
|
21
|
+
* @returns Removed track
|
|
18
22
|
*/
|
|
19
23
|
remove(identifier: number | string): Track | null;
|
|
20
24
|
/**
|
|
@@ -27,46 +31,48 @@ export class Queue {
|
|
|
27
31
|
clear(): void;
|
|
28
32
|
/**
|
|
29
33
|
* Jump to specific track
|
|
30
|
-
* @param
|
|
31
|
-
* @returns
|
|
34
|
+
* @param index - Track index
|
|
35
|
+
* @returns Track at index
|
|
32
36
|
*/
|
|
33
37
|
jump(index: number): Track | null;
|
|
34
38
|
/**
|
|
35
39
|
* Get current track
|
|
36
|
-
* @returns
|
|
40
|
+
* @returns Current track
|
|
37
41
|
*/
|
|
38
42
|
getCurrent(): Track | null;
|
|
39
43
|
/**
|
|
40
44
|
* Get next track
|
|
41
|
-
*
|
|
45
|
+
* Moves cursor forward
|
|
46
|
+
* @param loop - Whether to loop back to start
|
|
47
|
+
* @returns Next track
|
|
42
48
|
*/
|
|
43
|
-
|
|
49
|
+
next(loop?: boolean): Track | null;
|
|
44
50
|
/**
|
|
45
51
|
* Get previous track
|
|
46
|
-
*
|
|
52
|
+
* Moves cursor backward
|
|
53
|
+
* @param loop - Whether to loop to end
|
|
54
|
+
* @returns Previous track
|
|
47
55
|
*/
|
|
48
|
-
|
|
56
|
+
previous(loop?: boolean): Track | null;
|
|
49
57
|
/**
|
|
50
58
|
* Get all tracks
|
|
51
|
-
* @returns
|
|
59
|
+
* @returns Array of tracks
|
|
52
60
|
*/
|
|
53
61
|
getTracks(): Track[];
|
|
54
62
|
/**
|
|
55
63
|
* Get queue size
|
|
56
|
-
* @returns
|
|
64
|
+
* @returns Number of tracks
|
|
57
65
|
*/
|
|
58
66
|
size(): number;
|
|
59
67
|
/**
|
|
60
68
|
* Check if queue is empty
|
|
61
|
-
* @returns
|
|
69
|
+
* @returns Is empty
|
|
62
70
|
*/
|
|
63
71
|
isEmpty(): boolean;
|
|
64
72
|
/**
|
|
65
73
|
* Get track at index
|
|
66
|
-
* @param
|
|
67
|
-
* @returns
|
|
74
|
+
* @param index - Track index
|
|
75
|
+
* @returns Track at index
|
|
68
76
|
*/
|
|
69
77
|
getTrack(index: number): Track | null;
|
|
70
78
|
}
|
|
71
|
-
import { EventBus } from '../events/EventBus.js';
|
|
72
|
-
import { Track } from './Track.js';
|
|
@@ -1,32 +1,34 @@
|
|
|
1
|
+
import { ITrack } from '../interfaces';
|
|
1
2
|
/**
|
|
2
3
|
* Represents an audio track
|
|
3
4
|
*/
|
|
4
|
-
export class Track {
|
|
5
|
+
export declare class Track implements ITrack {
|
|
6
|
+
id: string;
|
|
7
|
+
url: string;
|
|
8
|
+
title: string;
|
|
9
|
+
artist?: string;
|
|
10
|
+
duration?: number;
|
|
11
|
+
thumbnail?: string;
|
|
12
|
+
source?: string;
|
|
13
|
+
metadata: Record<string, any>;
|
|
5
14
|
/**
|
|
6
|
-
* @param
|
|
7
|
-
* @param
|
|
15
|
+
* @param url - Track URL or file path
|
|
16
|
+
* @param options - Additional options
|
|
8
17
|
*/
|
|
9
|
-
constructor(url: string, options?:
|
|
10
|
-
url: string;
|
|
11
|
-
title: any;
|
|
12
|
-
artist: any;
|
|
13
|
-
duration: any;
|
|
14
|
-
thumbnail: any;
|
|
15
|
-
metadata: any;
|
|
16
|
-
id: any;
|
|
18
|
+
constructor(url: string, options?: Partial<ITrack>);
|
|
17
19
|
/**
|
|
18
20
|
* Get track info
|
|
19
|
-
* @returns
|
|
21
|
+
* @returns Track information
|
|
20
22
|
*/
|
|
21
|
-
getInfo():
|
|
23
|
+
getInfo(): ITrack;
|
|
22
24
|
/**
|
|
23
25
|
* Update track metadata
|
|
24
|
-
* @param
|
|
26
|
+
* @param metadata - New metadata
|
|
25
27
|
*/
|
|
26
|
-
updateMetadata(metadata:
|
|
28
|
+
updateMetadata(metadata: Partial<ITrack>): void;
|
|
27
29
|
/**
|
|
28
30
|
* Check if track is valid
|
|
29
|
-
* @returns
|
|
31
|
+
* @returns Is valid
|
|
30
32
|
*/
|
|
31
33
|
isValid(): boolean;
|
|
32
34
|
}
|
|
@@ -1,39 +1,35 @@
|
|
|
1
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
1
2
|
/**
|
|
2
3
|
* Logger utility with different levels
|
|
3
4
|
*/
|
|
4
|
-
export class Logger {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
info: number;
|
|
9
|
-
warn: number;
|
|
10
|
-
error: number;
|
|
11
|
-
};
|
|
12
|
-
currentLevel: any;
|
|
5
|
+
export declare class Logger {
|
|
6
|
+
private levels;
|
|
7
|
+
private currentLevel;
|
|
8
|
+
constructor(level?: LogLevel);
|
|
13
9
|
/**
|
|
14
10
|
* Set log level
|
|
15
|
-
* @param
|
|
11
|
+
* @param level - Log level (debug, info, warn, error)
|
|
16
12
|
*/
|
|
17
|
-
setLevel(level:
|
|
13
|
+
setLevel(level: LogLevel): void;
|
|
18
14
|
/**
|
|
19
15
|
* Debug log
|
|
20
|
-
* @param
|
|
16
|
+
* @param args - Arguments to log
|
|
21
17
|
*/
|
|
22
18
|
debug(...args: any[]): void;
|
|
23
19
|
/**
|
|
24
20
|
* Info log
|
|
25
|
-
* @param
|
|
21
|
+
* @param args - Arguments to log
|
|
26
22
|
*/
|
|
27
23
|
info(...args: any[]): void;
|
|
28
24
|
/**
|
|
29
25
|
* Warning log
|
|
30
|
-
* @param
|
|
26
|
+
* @param args - Arguments to log
|
|
31
27
|
*/
|
|
32
28
|
warn(...args: any[]): void;
|
|
33
29
|
/**
|
|
34
30
|
* Error log
|
|
35
|
-
* @param
|
|
31
|
+
* @param args - Arguments to log
|
|
36
32
|
*/
|
|
37
33
|
error(...args: any[]): void;
|
|
38
34
|
}
|
|
39
|
-
export const logger: Logger;
|
|
35
|
+
export declare const logger: Logger;
|
|
@@ -1,35 +1,36 @@
|
|
|
1
|
+
import { ITrack } from '../interfaces';
|
|
1
2
|
/**
|
|
2
3
|
* Metadata parsing utilities
|
|
3
4
|
*/
|
|
4
|
-
export class MetadataUtils {
|
|
5
|
+
export declare class MetadataUtils {
|
|
5
6
|
/**
|
|
6
7
|
* Extract basic metadata from URL or file path
|
|
7
|
-
* @param
|
|
8
|
-
* @returns
|
|
8
|
+
* @param source - URL or file path
|
|
9
|
+
* @returns Metadata object
|
|
9
10
|
*/
|
|
10
|
-
static extract(source: string):
|
|
11
|
+
static extract(source: string): Partial<ITrack>;
|
|
11
12
|
/**
|
|
12
13
|
* Extract title from source
|
|
13
|
-
* @param
|
|
14
|
-
* @returns
|
|
14
|
+
* @param source - Source string
|
|
15
|
+
* @returns Extracted title
|
|
15
16
|
*/
|
|
16
17
|
static extractTitle(source: string): string;
|
|
17
18
|
/**
|
|
18
19
|
* Extract YouTube metadata (basic)
|
|
19
|
-
* @param
|
|
20
|
-
* @returns
|
|
20
|
+
* @param url - YouTube URL
|
|
21
|
+
* @returns Metadata
|
|
21
22
|
*/
|
|
22
|
-
static extractYouTubeMetadata
|
|
23
|
+
private static extractYouTubeMetadata;
|
|
23
24
|
/**
|
|
24
25
|
* Extract SoundCloud metadata (basic)
|
|
25
|
-
* @param
|
|
26
|
-
* @returns
|
|
26
|
+
* @param url - SoundCloud URL
|
|
27
|
+
* @returns Metadata
|
|
27
28
|
*/
|
|
28
|
-
static extractSoundCloudMetadata
|
|
29
|
+
private static extractSoundCloudMetadata;
|
|
29
30
|
/**
|
|
30
31
|
* Extract file metadata (basic)
|
|
31
|
-
* @param
|
|
32
|
-
* @returns
|
|
32
|
+
* @param path - File path
|
|
33
|
+
* @returns Metadata
|
|
33
34
|
*/
|
|
34
|
-
static extractFileMetadata
|
|
35
|
+
private static extractFileMetadata;
|
|
35
36
|
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Audio probing utilities
|
|
3
3
|
*/
|
|
4
|
-
export class ProbeUtils {
|
|
4
|
+
export declare class ProbeUtils {
|
|
5
5
|
/**
|
|
6
6
|
* Probe audio file/stream for basic info
|
|
7
|
-
* @param
|
|
8
|
-
* @returns
|
|
7
|
+
* @param source - Audio source
|
|
8
|
+
* @returns Probe result
|
|
9
9
|
*/
|
|
10
10
|
static probe(source: string | Buffer | ReadableStream): Promise<any>;
|
|
11
11
|
/**
|
|
12
12
|
* Check if source is a valid audio URL
|
|
13
|
-
* @param
|
|
14
|
-
* @returns
|
|
13
|
+
* @param url - URL to check
|
|
14
|
+
* @returns Is valid audio URL
|
|
15
15
|
*/
|
|
16
16
|
static isValidAudioUrl(url: string): boolean;
|
|
17
17
|
/**
|
|
18
18
|
* Get audio format from URL or buffer
|
|
19
|
-
* @param
|
|
20
|
-
* @returns
|
|
19
|
+
* @param source - Audio source
|
|
20
|
+
* @returns Audio format
|
|
21
21
|
*/
|
|
22
22
|
static getFormat(source: string | Buffer): string | null;
|
|
23
23
|
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Time formatting utilities
|
|
3
3
|
*/
|
|
4
|
-
export class TimeUtils {
|
|
4
|
+
export declare class TimeUtils {
|
|
5
5
|
/**
|
|
6
6
|
* Format seconds to MM:SS or HH:MM:SS
|
|
7
|
-
* @param
|
|
8
|
-
* @returns
|
|
7
|
+
* @param seconds - Time in seconds
|
|
8
|
+
* @returns Formatted time string
|
|
9
9
|
*/
|
|
10
10
|
static format(seconds: number): string;
|
|
11
11
|
/**
|
|
12
12
|
* Parse time string to seconds
|
|
13
|
-
* @param
|
|
14
|
-
* @returns
|
|
13
|
+
* @param timeStr - Time string like "1:23" or "01:23:45"
|
|
14
|
+
* @returns Time in seconds
|
|
15
15
|
*/
|
|
16
16
|
static parse(timeStr: string): number;
|
|
17
17
|
/**
|
|
18
18
|
* Get current timestamp in milliseconds
|
|
19
|
-
* @returns
|
|
19
|
+
* @returns Current time
|
|
20
20
|
*/
|
|
21
21
|
static now(): number;
|
|
22
22
|
/**
|
|
23
23
|
* Calculate duration between two timestamps
|
|
24
|
-
* @param
|
|
25
|
-
* @param
|
|
26
|
-
* @returns
|
|
24
|
+
* @param start - Start time
|
|
25
|
+
* @param end - End time
|
|
26
|
+
* @returns Duration in milliseconds
|
|
27
27
|
*/
|
|
28
28
|
static duration(start: number, end: number): number;
|
|
29
29
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger utility with different levels
|
|
3
|
+
*/
|
|
4
|
+
export class Logger {
|
|
5
|
+
constructor(level = 'info') {
|
|
6
|
+
this.levels = {
|
|
7
|
+
debug: 0,
|
|
8
|
+
info: 1,
|
|
9
|
+
warn: 2,
|
|
10
|
+
error: 3
|
|
11
|
+
};
|
|
12
|
+
this.currentLevel = this.levels[level];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Set log level
|
|
16
|
+
* @param level - Log level (debug, info, warn, error)
|
|
17
|
+
*/
|
|
18
|
+
setLevel(level) {
|
|
19
|
+
this.currentLevel = this.levels[level] || this.levels.info;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Debug log
|
|
23
|
+
* @param args - Arguments to log
|
|
24
|
+
*/
|
|
25
|
+
debug(...args) {
|
|
26
|
+
if (this.currentLevel <= this.levels.debug) {
|
|
27
|
+
console.debug('[DEBUG]', ...args);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Info log
|
|
32
|
+
* @param args - Arguments to log
|
|
33
|
+
*/
|
|
34
|
+
info(...args) {
|
|
35
|
+
if (this.currentLevel <= this.levels.info) {
|
|
36
|
+
console.info('[INFO]', ...args);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Warning log
|
|
41
|
+
* @param args - Arguments to log
|
|
42
|
+
*/
|
|
43
|
+
warn(...args) {
|
|
44
|
+
if (this.currentLevel <= this.levels.warn) {
|
|
45
|
+
console.warn('[WARN]', ...args);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Error log
|
|
50
|
+
* @param args - Arguments to log
|
|
51
|
+
*/
|
|
52
|
+
error(...args) {
|
|
53
|
+
if (this.currentLevel <= this.levels.error) {
|
|
54
|
+
console.error('[ERROR]', ...args);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Default logger instance
|
|
59
|
+
export const logger = new Logger();
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata parsing utilities
|
|
3
|
+
*/
|
|
4
|
+
export class MetadataUtils {
|
|
5
|
+
/**
|
|
6
|
+
* Extract basic metadata from URL or file path
|
|
7
|
+
* @param source - URL or file path
|
|
8
|
+
* @returns Metadata object
|
|
9
|
+
*/
|
|
10
|
+
static extract(source) {
|
|
11
|
+
if (!source)
|
|
12
|
+
return {};
|
|
13
|
+
const metadata = {
|
|
14
|
+
title: this.extractTitle(source),
|
|
15
|
+
artist: undefined,
|
|
16
|
+
duration: undefined,
|
|
17
|
+
thumbnail: undefined
|
|
18
|
+
};
|
|
19
|
+
// For YouTube URLs
|
|
20
|
+
if (source.includes('youtube.com') || source.includes('youtu.be')) {
|
|
21
|
+
return this.extractYouTubeMetadata(source);
|
|
22
|
+
}
|
|
23
|
+
// For SoundCloud URLs
|
|
24
|
+
if (source.includes('soundcloud.com')) {
|
|
25
|
+
return this.extractSoundCloudMetadata(source);
|
|
26
|
+
}
|
|
27
|
+
// For local files
|
|
28
|
+
if (!source.startsWith('http')) {
|
|
29
|
+
return this.extractFileMetadata(source);
|
|
30
|
+
}
|
|
31
|
+
return metadata;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extract title from source
|
|
35
|
+
* @param source - Source string
|
|
36
|
+
* @returns Extracted title
|
|
37
|
+
*/
|
|
38
|
+
static extractTitle(source) {
|
|
39
|
+
if (!source)
|
|
40
|
+
return 'Unknown Track';
|
|
41
|
+
// Try to extract from URL query params
|
|
42
|
+
try {
|
|
43
|
+
const url = new URL(source);
|
|
44
|
+
const title = url.searchParams.get('title') || url.searchParams.get('name');
|
|
45
|
+
if (title)
|
|
46
|
+
return decodeURIComponent(title);
|
|
47
|
+
}
|
|
48
|
+
catch { } // eslint-disable-line no-empty
|
|
49
|
+
// Extract from file path
|
|
50
|
+
const parts = source.split('/').pop()?.split('\\').pop();
|
|
51
|
+
if (parts) {
|
|
52
|
+
return parts.replace(/\.[^/.]+$/, ''); // Remove extension
|
|
53
|
+
}
|
|
54
|
+
return 'Unknown Track';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extract YouTube metadata (basic)
|
|
58
|
+
* @param url - YouTube URL
|
|
59
|
+
* @returns Metadata
|
|
60
|
+
*/
|
|
61
|
+
static extractYouTubeMetadata(url) {
|
|
62
|
+
return {
|
|
63
|
+
title: 'YouTube Track',
|
|
64
|
+
source: 'youtube'
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Extract SoundCloud metadata (basic)
|
|
69
|
+
* @param url - SoundCloud URL
|
|
70
|
+
* @returns Metadata
|
|
71
|
+
*/
|
|
72
|
+
static extractSoundCloudMetadata(url) {
|
|
73
|
+
return {
|
|
74
|
+
title: 'SoundCloud Track',
|
|
75
|
+
source: 'soundcloud'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Extract file metadata (basic)
|
|
80
|
+
* @param path - File path
|
|
81
|
+
* @returns Metadata
|
|
82
|
+
*/
|
|
83
|
+
static extractFileMetadata(path) {
|
|
84
|
+
const title = this.extractTitle(path);
|
|
85
|
+
return {
|
|
86
|
+
title,
|
|
87
|
+
source: 'local'
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio probing utilities
|
|
3
|
+
*/
|
|
4
|
+
export class ProbeUtils {
|
|
5
|
+
/**
|
|
6
|
+
* Probe audio file/stream for basic info
|
|
7
|
+
* @param source - Audio source
|
|
8
|
+
* @returns Probe result
|
|
9
|
+
*/
|
|
10
|
+
static async probe(source) {
|
|
11
|
+
// In a real implementation, this would use ffprobe or similar
|
|
12
|
+
// For now, return basic mock data
|
|
13
|
+
return {
|
|
14
|
+
duration: null, // seconds
|
|
15
|
+
format: null, // e.g., 'mp3', 'wav'
|
|
16
|
+
bitrate: null, // kbps
|
|
17
|
+
sampleRate: null, // Hz
|
|
18
|
+
channels: null // 1 or 2
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if source is a valid audio URL
|
|
23
|
+
* @param url - URL to check
|
|
24
|
+
* @returns Is valid audio URL
|
|
25
|
+
*/
|
|
26
|
+
static isValidAudioUrl(url) {
|
|
27
|
+
if (!url || typeof url !== 'string')
|
|
28
|
+
return false;
|
|
29
|
+
try {
|
|
30
|
+
const parsed = new URL(url);
|
|
31
|
+
const audioExtensions = ['.mp3', '.wav', '.ogg', '.flac', '.aac', '.m4a'];
|
|
32
|
+
const path = parsed.pathname.toLowerCase();
|
|
33
|
+
return audioExtensions.some(ext => path.endsWith(ext)) ||
|
|
34
|
+
url.includes('youtube.com') ||
|
|
35
|
+
url.includes('youtu.be') ||
|
|
36
|
+
url.includes('soundcloud.com');
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get audio format from URL or buffer
|
|
44
|
+
* @param source - Audio source
|
|
45
|
+
* @returns Audio format
|
|
46
|
+
*/
|
|
47
|
+
static getFormat(source) {
|
|
48
|
+
if (typeof source === 'string') {
|
|
49
|
+
const extensions = ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a'];
|
|
50
|
+
for (const ext of extensions) {
|
|
51
|
+
if (source.toLowerCase().includes(`.${ext}`)) {
|
|
52
|
+
return ext;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// For buffer, would need to check headers
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
export class TimeUtils {
|
|
5
|
+
/**
|
|
6
|
+
* Format seconds to MM:SS or HH:MM:SS
|
|
7
|
+
* @param seconds - Time in seconds
|
|
8
|
+
* @returns Formatted time string
|
|
9
|
+
*/
|
|
10
|
+
static format(seconds) {
|
|
11
|
+
if (!Number.isFinite(seconds) || seconds < 0)
|
|
12
|
+
return '00:00';
|
|
13
|
+
const hours = Math.floor(seconds / 3600);
|
|
14
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
15
|
+
const secs = Math.floor(seconds % 60);
|
|
16
|
+
if (hours > 0) {
|
|
17
|
+
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
18
|
+
}
|
|
19
|
+
return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parse time string to seconds
|
|
23
|
+
* @param timeStr - Time string like "1:23" or "01:23:45"
|
|
24
|
+
* @returns Time in seconds
|
|
25
|
+
*/
|
|
26
|
+
static parse(timeStr) {
|
|
27
|
+
if (!timeStr)
|
|
28
|
+
return 0;
|
|
29
|
+
const parts = timeStr.split(':').map(Number);
|
|
30
|
+
if (parts.length === 2) {
|
|
31
|
+
return parts[0] * 60 + parts[1];
|
|
32
|
+
}
|
|
33
|
+
else if (parts.length === 3) {
|
|
34
|
+
return parts[0] * 3600 + parts[1] * 60 + parts[2];
|
|
35
|
+
}
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get current timestamp in milliseconds
|
|
40
|
+
* @returns Current time
|
|
41
|
+
*/
|
|
42
|
+
static now() {
|
|
43
|
+
return Date.now();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Calculate duration between two timestamps
|
|
47
|
+
* @param start - Start time
|
|
48
|
+
* @param end - End time
|
|
49
|
+
* @returns Duration in milliseconds
|
|
50
|
+
*/
|
|
51
|
+
static duration(start, end) {
|
|
52
|
+
return end - start;
|
|
53
|
+
}
|
|
54
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@students-dev/audify-js",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Modern modular audio engine with queue, filters, plugin API, and event-driven design.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cjs/index.js",
|
|
@@ -41,14 +41,24 @@
|
|
|
41
41
|
"url": "https://github.com/students-dev/audify-js/issues"
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://github.com/students-dev/audify-js#readme",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"lavalink-client": "^2.5.1",
|
|
46
|
+
"spotify-web-api-node": "^5.0.1"
|
|
47
|
+
},
|
|
44
48
|
"devDependencies": {
|
|
45
|
-
"@rollup/plugin-
|
|
46
|
-
"@rollup/plugin-
|
|
47
|
-
"rollup": "^
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"eslint": "^8.
|
|
49
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
50
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
51
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
52
|
+
"@types/jest": "^30.0.0",
|
|
53
|
+
"@types/node": "^25.0.3",
|
|
54
|
+
"@types/spotify-web-api-node": "^5.0.11",
|
|
55
|
+
"eslint": "^8.56.0",
|
|
56
|
+
"jest": "^29.7.0",
|
|
57
|
+
"rollup": "^4.9.6",
|
|
58
|
+
"rollup-plugin-dts": "^6.1.0",
|
|
59
|
+
"ts-jest": "^29.4.6",
|
|
60
|
+
"tslib": "^2.8.1",
|
|
61
|
+
"typescript": "^5.3.3"
|
|
52
62
|
},
|
|
53
63
|
"engines": {
|
|
54
64
|
"node": ">=14.0.0"
|
|
@@ -57,4 +67,4 @@
|
|
|
57
67
|
"dist",
|
|
58
68
|
"README.md"
|
|
59
69
|
]
|
|
60
|
-
}
|
|
70
|
+
}
|