@ziplayer/plugin 0.1.40 → 0.1.50

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/README.md CHANGED
@@ -8,6 +8,7 @@ Official plugin bundle for ZiPlayer. It ships a set of ready‑to‑use source p
8
8
  - SoundCloudPlugin: search + stream SoundCloud tracks and sets
9
9
  - SpotifyPlugin: resolve tracks/albums/playlists, stream via fallbacks
10
10
  - TTSPlugin: Text‑to‑Speech playback from simple `tts:` queries
11
+ - AttachmentsPlugin: handle Discord attachment URLs and direct audio file URLs
11
12
 
12
13
  ZiPlayer is an audio player built on top of `@discordjs/voice` and `discord.js`. This package provides sources; the core player
13
14
  lives in `ziplayer`.
@@ -28,15 +29,16 @@ npm install @zibot/zitts axios
28
29
 
29
30
  ```ts
30
31
  import { PlayerManager } from "ziplayer";
31
- import { YouTubePlugin, SoundCloudPlugin, SpotifyPlugin, TTSPlugin } from "@ziplayer/plugin";
32
+ import { YouTubePlugin, SoundCloudPlugin, SpotifyPlugin, TTSPlugin, AttachmentsPlugin } from "@ziplayer/plugin";
32
33
 
33
34
  const manager = new PlayerManager({
34
35
  plugins: [
35
- // Order matters: put more specific handlers first (e.g., TTS)
36
+ // Order matters: put more specific handlers first (e.g., TTS, Attachments)
36
37
  new TTSPlugin({ defaultLang: "en" }),
37
38
  new YouTubePlugin(),
38
39
  new SoundCloudPlugin(),
39
40
  new SpotifyPlugin(),
41
+ new AttachmentsPlugin({ maxFileSize: 25 * 1024 * 1024 }), //25mb
40
42
  ],
41
43
  });
42
44
 
@@ -53,6 +55,9 @@ await player.play("https://www.youtube.com/playlist?list=...", requestedBy);
53
55
  // Speak with TTS
54
56
  await player.play("tts:en:Hello there!", requestedBy);
55
57
 
58
+ // Play Discord attachment
59
+ await player.play("https://cdn.discordapp.com/attachments/123/456/audio.mp3", requestedBy);
60
+
56
61
  // Handle events via the manager
57
62
  manager.on("trackStart", (plr, track) => {
58
63
  plr.userdata?.channel?.send?.(`Now playing: ${track.title}`);
@@ -93,6 +98,7 @@ const sp = new SpotifyPlugin();
93
98
  ### TTSPlugin (Text‑to‑Speech)
94
99
 
95
100
  - Plays spoken audio from text using a lightweight Google TTS wrapper.
101
+ - **Accurate duration analysis**: Generates sample audio to measure actual duration instead of estimating.
96
102
  - Supported query formats:
97
103
  - `tts: <text>`
98
104
  - `tts:<lang>:<text>` (e.g., `tts:vi:xin chao`)
@@ -101,6 +107,13 @@ const sp = new SpotifyPlugin();
101
107
  ```ts
102
108
  import { TTSPlugin } from "@ziplayer/plugin";
103
109
  const tts = new TTSPlugin({ defaultLang: "en", slow: false });
110
+
111
+ // The plugin automatically analyzes TTS duration
112
+ const result = await tts.search("tts:en:Hello world", "user123");
113
+ console.log(`Duration: ${result.tracks[0].duration}s`); // Real duration from audio analysis
114
+ console.log(`Language: ${result.tracks[0].metadata.language}`); // "en"
115
+ console.log(`Slow mode: ${result.tracks[0].metadata.slowMode}`); // false
116
+
104
117
  await player.play("tts:en:1:good morning", requestedBy);
105
118
  ```
106
119
 
@@ -124,6 +137,29 @@ const tts = new TTSPlugin({
124
137
  });
125
138
  ```
126
139
 
140
+ ### AttachmentsPlugin
141
+
142
+ - Handles Discord attachment URLs and direct audio file URLs.
143
+ - Supports various audio formats (mp3, wav, ogg, m4a, flac, etc.).
144
+ - **Audio metadata analysis**: Extracts duration, title, artist, album, bitrate, etc.
145
+ - Includes file size validation and proper error handling.
146
+ - Uses Range requests to efficiently analyze metadata without downloading entire files.
147
+
148
+ ```ts
149
+ import { AttachmentsPlugin } from "@ziplayer/plugin";
150
+ const attachments = new AttachmentsPlugin({
151
+ maxFileSize: 25 * 1024 * 1024, // 25MB
152
+ allowedExtensions: ["mp3", "wav", "ogg", "m4a", "flac"],
153
+ debug: true, // Enable to see metadata analysis process
154
+ });
155
+
156
+ // The plugin automatically analyzes audio metadata
157
+ const result = await attachments.search("https://cdn.discordapp.com/attachments/123/456/song.mp3", "user123");
158
+ console.log(`Duration: ${result.tracks[0].duration}s`); // Real duration from metadata
159
+ console.log(`Title: ${result.tracks[0].title}`); // May be extracted from metadata
160
+ console.log(`Artist: ${result.tracks[0].metadata.artist}`); // From metadata
161
+ ```
162
+
127
163
  ## Writing Your Own Plugin
128
164
 
129
165
  Plugins implement the `BasePlugin` contract from `ziplayer`:
@@ -0,0 +1,192 @@
1
+ import { BasePlugin, Track, SearchResult, StreamInfo } from "ziplayer";
2
+ /**
3
+ * Configuration options for the AttachmentsPlugin.
4
+ */
5
+ export interface AttachmentsPluginOptions {
6
+ /** Maximum file size in bytes (default: 25MB) */
7
+ maxFileSize?: number;
8
+ /** Allowed audio file extensions */
9
+ allowedExtensions?: string[];
10
+ /** Whether to enable debug logging */
11
+ debug?: boolean;
12
+ }
13
+ /**
14
+ * A plugin for handling Discord attachment URLs and local audio files.
15
+ *
16
+ * This plugin provides support for:
17
+ * - Discord attachment URLs (cdn.discordapp.com, media.discordapp.net)
18
+ * - Direct audio file URLs
19
+ * - Local file paths (if accessible)
20
+ * - Various audio formats (mp3, wav, ogg, m4a, flac, etc.)
21
+ * - File size validation
22
+ * - Audio metadata analysis (duration, title, artist, album, etc.)
23
+ * - Stream extraction from URLs
24
+ *
25
+ * @example
26
+ * const attachmentsPlugin = new AttachmentsPlugin({
27
+ * maxFileSize: 25 * 1024 * 1024, // 25MB
28
+ * allowedExtensions: ['mp3', 'wav', 'ogg', 'm4a', 'flac']
29
+ * });
30
+ *
31
+ * // Add to PlayerManager
32
+ * const manager = new PlayerManager({
33
+ * plugins: [attachmentsPlugin]
34
+ * });
35
+ *
36
+ * // Search for attachment content
37
+ * const result = await attachmentsPlugin.search(
38
+ * "https://cdn.discordapp.com/attachments/123/456/audio.mp3",
39
+ * "user123"
40
+ * );
41
+ * const stream = await attachmentsPlugin.getStream(result.tracks[0]);
42
+ *
43
+ * @since 1.0.0
44
+ */
45
+ export declare class AttachmentsPlugin extends BasePlugin {
46
+ name: string;
47
+ version: string;
48
+ private opts;
49
+ private readonly defaultAllowedExtensions;
50
+ /**
51
+ * Creates a new AttachmentsPlugin instance.
52
+ *
53
+ * @param opts - Configuration options for the attachments plugin
54
+ * @param opts.maxFileSize - Maximum file size in bytes (default: 25MB)
55
+ * @param opts.allowedExtensions - Allowed audio file extensions (default: common audio formats)
56
+ * @param opts.debug - Whether to enable debug logging (default: false)
57
+ *
58
+ * @example
59
+ * // Basic attachments plugin
60
+ * const attachmentsPlugin = new AttachmentsPlugin();
61
+ *
62
+ * // Custom configuration
63
+ * const customPlugin = new AttachmentsPlugin({
64
+ * maxFileSize: 50 * 1024 * 1024, // 50MB
65
+ * allowedExtensions: ['mp3', 'wav', 'ogg'],
66
+ * debug: true
67
+ * });
68
+ */
69
+ constructor(opts?: AttachmentsPluginOptions);
70
+ /**
71
+ * Determines if this plugin can handle the given query.
72
+ *
73
+ * @param query - The URL or file path to check
74
+ * @returns `true` if the query is a Discord attachment URL or audio file URL, `false` otherwise
75
+ *
76
+ * @example
77
+ * plugin.canHandle("https://cdn.discordapp.com/attachments/123/456/audio.mp3"); // true
78
+ * plugin.canHandle("https://example.com/song.wav"); // true
79
+ * plugin.canHandle("youtube.com/watch?v=123"); // false
80
+ */
81
+ canHandle(query: string): boolean;
82
+ /**
83
+ * Validates if a URL is a valid Discord attachment URL or audio file URL.
84
+ *
85
+ * @param url - The URL to validate
86
+ * @returns `true` if the URL is valid and points to an audio file, `false` otherwise
87
+ *
88
+ * @example
89
+ * plugin.validate("https://cdn.discordapp.com/attachments/123/456/audio.mp3"); // true
90
+ * plugin.validate("https://example.com/song.wav"); // true
91
+ * plugin.validate("https://example.com/image.jpg"); // false
92
+ */
93
+ validate(url: string): boolean;
94
+ /**
95
+ * Creates a track from an attachment URL or file path.
96
+ *
97
+ * This method handles both Discord attachment URLs and direct audio file URLs.
98
+ * It extracts metadata from the URL and creates a track that can be played.
99
+ *
100
+ * @param query - The attachment URL or file path
101
+ * @param requestedBy - The user ID who requested the track
102
+ * @returns A SearchResult containing a single track
103
+ *
104
+ * @example
105
+ * // Discord attachment
106
+ * const result = await plugin.search(
107
+ * "https://cdn.discordapp.com/attachments/123/456/audio.mp3",
108
+ * "user123"
109
+ * );
110
+ *
111
+ * // Direct audio file URL
112
+ * const result2 = await plugin.search(
113
+ * "https://example.com/song.wav",
114
+ * "user123"
115
+ * );
116
+ */
117
+ search(query: string, requestedBy: string): Promise<SearchResult>;
118
+ /**
119
+ * Retrieves the audio stream from an attachment URL or file path.
120
+ *
121
+ * This method downloads the audio file from the URL and returns it as a stream.
122
+ * It handles various audio formats and provides proper error handling.
123
+ *
124
+ * @param track - The Track object to get the stream for
125
+ * @returns A StreamInfo object containing the audio stream
126
+ * @throws {Error} If the URL is invalid, file is too large, or download fails
127
+ *
128
+ * @example
129
+ * const track = {
130
+ * id: "attachment-123",
131
+ * title: "audio.mp3",
132
+ * url: "https://cdn.discordapp.com/attachments/123/456/audio.mp3",
133
+ * ...
134
+ * };
135
+ * const streamInfo = await plugin.getStream(track);
136
+ * console.log(streamInfo.type); // "arbitrary"
137
+ * console.log(streamInfo.stream); // Readable stream
138
+ */
139
+ getStream(track: Track): Promise<StreamInfo>;
140
+ /**
141
+ * Provides a fallback by attempting to re-download the file.
142
+ *
143
+ * @param track - The Track object to get a fallback stream for
144
+ * @returns A StreamInfo object containing the fallback audio stream
145
+ * @throws {Error} If fallback download fails
146
+ */
147
+ getFallback(track: Track): Promise<StreamInfo>;
148
+ /**
149
+ * Checks if a file path or URL is an audio file based on extension.
150
+ */
151
+ private isAudioFile;
152
+ /**
153
+ * Extracts the file extension from a path or URL.
154
+ */
155
+ private getFileExtension;
156
+ /**
157
+ * Extracts filename from a URL or path.
158
+ */
159
+ private extractFilename;
160
+ /**
161
+ * Checks if a URL is a Discord attachment URL.
162
+ */
163
+ private isDiscordAttachment;
164
+ /**
165
+ * Generates a unique track ID for a given URL.
166
+ */
167
+ private generateTrackId;
168
+ /**
169
+ * Simple hash function for generating IDs.
170
+ */
171
+ private simpleHash;
172
+ /**
173
+ * Determines the appropriate stream type based on content type and file extension.
174
+ */
175
+ private getStreamType;
176
+ /**
177
+ * Formats bytes into a human-readable string.
178
+ */
179
+ private formatBytes;
180
+ /**
181
+ * Analyzes audio metadata to extract duration and other information.
182
+ *
183
+ * @param url - The URL to analyze
184
+ * @returns Promise containing duration in seconds and metadata
185
+ */
186
+ private analyzeAudioMetadata;
187
+ /**
188
+ * Debug logging helper.
189
+ */
190
+ private debug;
191
+ }
192
+ //# sourceMappingURL=AttachmentsPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttachmentsPlugin.d.ts","sourceRoot":"","sources":["../src/AttachmentsPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAKvE;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACxC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,sCAAsC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;IAChD,IAAI,SAAiB;IACrB,OAAO,SAAW;IAElB,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAsE;IAE/G;;;;;;;;;;;;;;;;;;OAkBG;gBACS,IAAI,CAAC,EAAE,wBAAwB;IAS3C;;;;;;;;;;OAUG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IA8BjC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA0EvE;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;IA0DlD;;;;;;OAMG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;IAKpD;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB;;OAEG;IACH,OAAO,CAAC,aAAa;IAgBrB;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;;;;OAKG;YACW,oBAAoB;IA2ElC;;OAEG;IACH,OAAO,CAAC,KAAK;CAKb"}