ziplayer 0.2.6 → 0.2.7-dev.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.
@@ -1,190 +1,190 @@
1
- import type { Player } from "../structures/Player";
2
- import type { PlayerManager } from "../structures/PlayerManager";
3
- import type {
4
- ExtensionSearchRequest,
5
- SearchResult,
6
- StreamInfo,
7
- Track,
8
- ExtensionContext,
9
- ExtensionPlayRequest,
10
- ExtensionPlayResponse,
11
- ExtensionAfterPlayPayload,
12
- ExtensionStreamRequest,
13
- } from "../types";
14
-
15
- import { BaseExtension } from "./BaseExtension";
16
-
17
- export { BaseExtension } from "./BaseExtension";
18
-
19
- // Extension factory
20
- export class ExtensionManager {
21
- private extensions: Map<string, BaseExtension>;
22
- private player: Player;
23
- private manager: PlayerManager;
24
- private extensionContext: ExtensionContext;
25
-
26
- constructor(player: Player, manager: PlayerManager) {
27
- this.player = player;
28
- this.manager = manager;
29
- this.extensions = new Map();
30
- this.extensionContext = Object.freeze({ player, manager });
31
- }
32
- debug(message?: any, ...optionalParams: any[]): void {
33
- if (this.manager.debugEnabled) {
34
- this.manager.emit("debug", `[ExtensionManager] ${message}`, ...optionalParams);
35
- }
36
- }
37
-
38
- register(extension: BaseExtension): void {
39
- if (this.extensions.has(extension.name)) {
40
- return;
41
- }
42
- if (!extension.player) {
43
- extension.player = this.player;
44
- }
45
- this.extensions.set(extension.name, extension);
46
- }
47
-
48
- unregister(extension: BaseExtension): boolean {
49
- const name = extension.name;
50
- const result = this.extensions.delete(name);
51
- if (result) {
52
- this.invokeExtensionLifecycle(extension, "onDestroy");
53
- }
54
- return result;
55
- }
56
-
57
- destroy(): void {
58
- this.debug(`[ExtensionManager] destroying all extensions`);
59
- for (const extension of this.extensions.values()) {
60
- this.unregister(extension);
61
- }
62
- this.extensions.clear();
63
- }
64
-
65
- get(name: string): BaseExtension | undefined {
66
- return this.extensions.get(name);
67
- }
68
-
69
- getAll(): BaseExtension[] {
70
- return Array.from(this.extensions.values());
71
- }
72
-
73
- findExtension(alas: any): BaseExtension | undefined {
74
- return this.getAll().find((extension) => extension.active(alas));
75
- }
76
-
77
- clear(): void {
78
- this.extensions.clear();
79
- }
80
-
81
- private invokeExtensionLifecycle(extension: BaseExtension | undefined, hook: "onRegister" | "onDestroy"): void {
82
- if (!extension) return;
83
- const fn = (extension as any)[hook];
84
- if (typeof fn !== "function") return;
85
- try {
86
- const result = fn.call(extension, this.extensionContext);
87
- if (result && typeof (result as Promise<unknown>).then === "function") {
88
- (result as Promise<unknown>).catch((err) => this.debug(`[Player] Extension ${extension.name} ${hook} error:`, err));
89
- }
90
- } catch (err) {
91
- this.debug(`[Player] Extension ${extension.name} ${hook} error:`, err);
92
- }
93
- }
94
-
95
- async provideSearch(query: string, requestedBy: string): Promise<SearchResult | null> {
96
- const request: ExtensionSearchRequest = { query, requestedBy };
97
- for (const extension of this.getAll()) {
98
- const hook = (extension as any).provideSearch;
99
- if (typeof hook !== "function") continue;
100
- try {
101
- const result = await Promise.resolve(hook.call(extension, this.extensionContext, request));
102
- if (result && Array.isArray(result.tracks) && result.tracks.length > 0) {
103
- this.debug(`[Player] Extension ${extension.name} handled search for query: ${query}`);
104
- return result as SearchResult;
105
- }
106
- } catch (err) {
107
- this.debug(`[Player] Extension ${extension.name} provideSearch error:`, err);
108
- }
109
- }
110
- return null;
111
- }
112
-
113
- async provideStream(track: Track): Promise<StreamInfo | null> {
114
- const request: ExtensionStreamRequest = { track };
115
- for (const extension of this.getAll()) {
116
- const hook = (extension as any).provideStream;
117
- if (typeof hook !== "function") continue;
118
- try {
119
- const result = await Promise.resolve(hook.call(extension, this.extensionContext, request));
120
- if (result && (result as StreamInfo).stream) {
121
- this.debug(`[Player] Extension ${extension.name} provided stream for track: ${track.title}`);
122
- return result as StreamInfo;
123
- }
124
- } catch (err) {
125
- this.debug(`[Player] Extension ${extension.name} provideStream error:`, err);
126
- }
127
- }
128
- return null;
129
- }
130
-
131
- async BeforePlayHooks(
132
- initial: ExtensionPlayRequest,
133
- ): Promise<{ request: ExtensionPlayRequest; response: ExtensionPlayResponse }> {
134
- const request: ExtensionPlayRequest = { ...initial };
135
- const response: ExtensionPlayResponse = {};
136
- for (const extension of this.getAll()) {
137
- const hook = (extension as any).beforePlay;
138
- if (typeof hook !== "function") continue;
139
- try {
140
- const result = await Promise.resolve(hook.call(extension, this.extensionContext, request));
141
- if (!result) continue;
142
- if (result.query !== undefined) {
143
- request.query = result.query;
144
- response.query = result.query;
145
- }
146
- if (result.requestedBy !== undefined) {
147
- request.requestedBy = result.requestedBy;
148
- response.requestedBy = result.requestedBy;
149
- }
150
- if (Array.isArray(result.tracks)) {
151
- response.tracks = result.tracks;
152
- }
153
- if (typeof result.isPlaylist === "boolean") {
154
- response.isPlaylist = result.isPlaylist;
155
- }
156
- if (typeof result.success === "boolean") {
157
- response.success = result.success;
158
- }
159
- if (result.error instanceof Error) {
160
- response.error = result.error;
161
- }
162
- if (typeof result.handled === "boolean") {
163
- response.handled = result.handled;
164
- if (result.handled) break;
165
- }
166
- } catch (err) {
167
- this.debug(`[Player] Extension ${extension.name} beforePlay error:`, err);
168
- }
169
- }
170
- return { request, response };
171
- }
172
-
173
- async AfterPlayHooks(payload: ExtensionAfterPlayPayload): Promise<void> {
174
- if (this.getAll().length === 0) return;
175
- const safeTracks = payload.tracks ? [...payload.tracks] : undefined;
176
- if (safeTracks) {
177
- Object.freeze(safeTracks);
178
- }
179
- const immutablePayload = Object.freeze({ ...payload, tracks: safeTracks });
180
- for (const extension of this.getAll()) {
181
- const hook = (extension as any).afterPlay;
182
- if (typeof hook !== "function") continue;
183
- try {
184
- await Promise.resolve(hook.call(extension, this.extensionContext, immutablePayload));
185
- } catch (err) {
186
- this.debug(`[Player] Extension ${extension.name} afterPlay error:`, err);
187
- }
188
- }
189
- }
190
- }
1
+ import type { Player } from "../structures/Player";
2
+ import type { PlayerManager } from "../structures/PlayerManager";
3
+ import type {
4
+ ExtensionSearchRequest,
5
+ SearchResult,
6
+ StreamInfo,
7
+ Track,
8
+ ExtensionContext,
9
+ ExtensionPlayRequest,
10
+ ExtensionPlayResponse,
11
+ ExtensionAfterPlayPayload,
12
+ ExtensionStreamRequest,
13
+ } from "../types";
14
+
15
+ import { BaseExtension } from "./BaseExtension";
16
+
17
+ export { BaseExtension } from "./BaseExtension";
18
+
19
+ // Extension factory
20
+ export class ExtensionManager {
21
+ private extensions: Map<string, BaseExtension>;
22
+ private player: Player;
23
+ private manager: PlayerManager;
24
+ private extensionContext: ExtensionContext;
25
+
26
+ constructor(player: Player, manager: PlayerManager) {
27
+ this.player = player;
28
+ this.manager = manager;
29
+ this.extensions = new Map();
30
+ this.extensionContext = Object.freeze({ player, manager });
31
+ }
32
+ debug(message?: any, ...optionalParams: any[]): void {
33
+ if (this.manager.debugEnabled) {
34
+ this.manager.emit("debug", `[ExtensionManager] ${message}`, ...optionalParams);
35
+ }
36
+ }
37
+
38
+ register(extension: BaseExtension): void {
39
+ if (this.extensions.has(extension.name)) {
40
+ return;
41
+ }
42
+ if (!extension.player) {
43
+ extension.player = this.player;
44
+ }
45
+ this.extensions.set(extension.name, extension);
46
+ }
47
+
48
+ unregister(extension: BaseExtension): boolean {
49
+ const name = extension.name;
50
+ const result = this.extensions.delete(name);
51
+ if (result) {
52
+ this.invokeExtensionLifecycle(extension, "onDestroy");
53
+ }
54
+ return result;
55
+ }
56
+
57
+ destroy(): void {
58
+ this.debug(`[ExtensionManager] destroying all extensions`);
59
+ for (const extension of this.extensions.values()) {
60
+ this.unregister(extension);
61
+ }
62
+ this.extensions.clear();
63
+ }
64
+
65
+ get(name: string): BaseExtension | undefined {
66
+ return this.extensions.get(name);
67
+ }
68
+
69
+ getAll(): BaseExtension[] {
70
+ return Array.from(this.extensions.values());
71
+ }
72
+
73
+ findExtension(alas: any): BaseExtension | undefined {
74
+ return this.getAll().find((extension) => extension.active(alas));
75
+ }
76
+
77
+ clear(): void {
78
+ this.extensions.clear();
79
+ }
80
+
81
+ private invokeExtensionLifecycle(extension: BaseExtension | undefined, hook: "onRegister" | "onDestroy"): void {
82
+ if (!extension) return;
83
+ const fn = (extension as any)[hook];
84
+ if (typeof fn !== "function") return;
85
+ try {
86
+ const result = fn.call(extension, this.extensionContext);
87
+ if (result && typeof (result as Promise<unknown>).then === "function") {
88
+ (result as Promise<unknown>).catch((err) => this.debug(`[Player] Extension ${extension.name} ${hook} error:`, err));
89
+ }
90
+ } catch (err) {
91
+ this.debug(`[Player] Extension ${extension.name} ${hook} error:`, err);
92
+ }
93
+ }
94
+
95
+ async provideSearch(query: string, requestedBy: string): Promise<SearchResult | null> {
96
+ const request: ExtensionSearchRequest = { query, requestedBy };
97
+ for (const extension of this.getAll()) {
98
+ const hook = (extension as any).provideSearch;
99
+ if (typeof hook !== "function") continue;
100
+ try {
101
+ const result = await Promise.resolve(hook.call(extension, this.extensionContext, request));
102
+ if (result && Array.isArray(result.tracks) && result.tracks.length > 0) {
103
+ this.debug(`[Player] Extension ${extension.name} handled search for query: ${query}`);
104
+ return result as SearchResult;
105
+ }
106
+ } catch (err) {
107
+ this.debug(`[Player] Extension ${extension.name} provideSearch error:`, err);
108
+ }
109
+ }
110
+ return null;
111
+ }
112
+
113
+ async provideStream(track: Track): Promise<StreamInfo | null> {
114
+ const request: ExtensionStreamRequest = { track };
115
+ for (const extension of this.getAll()) {
116
+ const hook = (extension as any).provideStream;
117
+ if (typeof hook !== "function") continue;
118
+ try {
119
+ const result = await Promise.resolve(hook.call(extension, this.extensionContext, request));
120
+ if (result && (result as StreamInfo).stream) {
121
+ this.debug(`[Player] Extension ${extension.name} provided stream for track: ${track.title}`);
122
+ return result as StreamInfo;
123
+ }
124
+ } catch (err) {
125
+ this.debug(`[Player] Extension ${extension.name} provideStream error:`, err);
126
+ }
127
+ }
128
+ return null;
129
+ }
130
+
131
+ async BeforePlayHooks(
132
+ initial: ExtensionPlayRequest,
133
+ ): Promise<{ request: ExtensionPlayRequest; response: ExtensionPlayResponse }> {
134
+ const request: ExtensionPlayRequest = { ...initial };
135
+ const response: ExtensionPlayResponse = {};
136
+ for (const extension of this.getAll()) {
137
+ const hook = (extension as any).beforePlay;
138
+ if (typeof hook !== "function") continue;
139
+ try {
140
+ const result = await Promise.resolve(hook.call(extension, this.extensionContext, request));
141
+ if (!result) continue;
142
+ if (result.query !== undefined) {
143
+ request.query = result.query;
144
+ response.query = result.query;
145
+ }
146
+ if (result.requestedBy !== undefined) {
147
+ request.requestedBy = result.requestedBy;
148
+ response.requestedBy = result.requestedBy;
149
+ }
150
+ if (Array.isArray(result.tracks)) {
151
+ response.tracks = result.tracks;
152
+ }
153
+ if (typeof result.isPlaylist === "boolean") {
154
+ response.isPlaylist = result.isPlaylist;
155
+ }
156
+ if (typeof result.success === "boolean") {
157
+ response.success = result.success;
158
+ }
159
+ if (result.error instanceof Error) {
160
+ response.error = result.error;
161
+ }
162
+ if (typeof result.handled === "boolean") {
163
+ response.handled = result.handled;
164
+ if (result.handled) break;
165
+ }
166
+ } catch (err) {
167
+ this.debug(`[Player] Extension ${extension.name} beforePlay error:`, err);
168
+ }
169
+ }
170
+ return { request, response };
171
+ }
172
+
173
+ async AfterPlayHooks(payload: ExtensionAfterPlayPayload): Promise<void> {
174
+ if (this.getAll().length === 0) return;
175
+ const safeTracks = payload.tracks ? [...payload.tracks] : undefined;
176
+ if (safeTracks) {
177
+ Object.freeze(safeTracks);
178
+ }
179
+ const immutablePayload = Object.freeze({ ...payload, tracks: safeTracks });
180
+ for (const extension of this.getAll()) {
181
+ const hook = (extension as any).afterPlay;
182
+ if (typeof hook !== "function") continue;
183
+ try {
184
+ await Promise.resolve(hook.call(extension, this.extensionContext, immutablePayload));
185
+ } catch (err) {
186
+ this.debug(`[Player] Extension ${extension.name} afterPlay error:`, err);
187
+ }
188
+ }
189
+ }
190
+ }
package/src/index.ts CHANGED
@@ -1,16 +1,16 @@
1
- import { PlayerManager, getGlobalManager } from "./structures/PlayerManager";
2
- import type { PlayerManagerOptions } from "./types";
3
-
4
- export { Player } from "./structures/Player";
5
- export { Queue } from "./structures/Queue";
6
- export { PlayerManager } from "./structures/PlayerManager";
7
- export * from "./types";
8
- export * from "./plugins";
9
- export * from "./extensions";
10
-
11
- // Default export
12
- export default PlayerManager;
13
-
14
- // Simple shared-instance accessor
15
- export const getManager = () => getGlobalManager();
16
- export const getPlayer = (guildOrId: string) => getManager()?.get(guildOrId);
1
+ import { PlayerManager, getGlobalManager } from "./structures/PlayerManager";
2
+ import type { PlayerManagerOptions } from "./types";
3
+
4
+ export { Player } from "./structures/Player";
5
+ export { Queue } from "./structures/Queue";
6
+ export { PlayerManager } from "./structures/PlayerManager";
7
+ export * from "./types";
8
+ export * from "./plugins";
9
+ export * from "./extensions";
10
+
11
+ // Default export
12
+ export default PlayerManager;
13
+
14
+ // Simple shared-instance accessor
15
+ export const getManager = () => getGlobalManager();
16
+ export const getPlayer = (guildOrId: string) => getManager()?.get(guildOrId);
@@ -1,27 +1,27 @@
1
- import { SourcePlugin, Track, SearchResult, StreamInfo } from "../types";
2
-
3
- export abstract class BasePlugin implements SourcePlugin {
4
- abstract name: string;
5
- abstract version: string;
6
- priority?: number = 0;
7
-
8
- abstract canHandle(query: string): boolean;
9
- abstract search(query: string, requestedBy: string): Promise<SearchResult>;
10
- abstract getStream(track: Track, signal?: AbortSignal): Promise<StreamInfo>;
11
-
12
- getFallback?(track: Track, signal?: AbortSignal): Promise<StreamInfo> {
13
- throw new Error("getFallback not implemented");
14
- }
15
-
16
- getRelatedTracks?(trackURL: Track, opts?: { limit?: number; offset?: number; history?: Track[] }): Promise<Track[]> {
17
- return Promise.resolve([]);
18
- }
19
-
20
- validate?(url: string): boolean {
21
- return this.canHandle(url);
22
- }
23
-
24
- extractPlaylist?(url: string, requestedBy: string): Promise<Track[]> {
25
- return Promise.resolve([]);
26
- }
27
- }
1
+ import { SourcePlugin, Track, SearchResult, StreamInfo } from "../types";
2
+
3
+ export abstract class BasePlugin implements SourcePlugin {
4
+ abstract name: string;
5
+ abstract version: string;
6
+ priority?: number = 0;
7
+
8
+ abstract canHandle(query: string): boolean;
9
+ abstract search(query: string, requestedBy: string): Promise<SearchResult>;
10
+ abstract getStream(track: Track, signal?: AbortSignal): Promise<StreamInfo>;
11
+
12
+ getFallback?(track: Track, signal?: AbortSignal): Promise<StreamInfo> {
13
+ throw new Error("getFallback not implemented");
14
+ }
15
+
16
+ getRelatedTracks?(trackURL: Track, opts?: { limit?: number; offset?: number; history?: Track[] }): Promise<Track[]> {
17
+ return Promise.resolve([]);
18
+ }
19
+
20
+ validate?(url: string): boolean {
21
+ return this.canHandle(url);
22
+ }
23
+
24
+ extractPlaylist?(url: string, requestedBy: string): Promise<Track[]> {
25
+ return Promise.resolve([]);
26
+ }
27
+ }