@ziplayer/plugin 0.0.5 → 0.1.1

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/YTSR_README.md ADDED
@@ -0,0 +1,310 @@
1
+ # YTSRPlugin - Plugin Tìm Kiếm Nâng Cao YouTube
2
+
3
+ YTSRPlugin là một plugin mạnh mẽ cho ZiPlayer, cung cấp khả năng tìm kiếm nâng cao trên YouTube mà không cần tạo stream. Plugin
4
+ này sử dụng thư viện `youtube-sr` để tìm kiếm và trích xuất metadata từ YouTube.
5
+
6
+ ## ✨ Tính Năng
7
+
8
+ - 🔍 **Tìm kiếm video nâng cao** với nhiều tùy chọn lọc
9
+ - 📋 **Tìm kiếm playlist** và channel
10
+ - 🎯 **Hỗ trợ nhiều loại tìm kiếm**: video, playlist, channel, hoặc tất cả
11
+ - ⏱️ **Lọc theo thời lượng**: short (< 4 phút), medium (4-20 phút), long (> 20 phút)
12
+ - 📅 **Lọc theo ngày upload**: hour, today, week, month, year
13
+ - 📊 **Sắp xếp kết quả**: relevance, uploadDate, viewCount, rating
14
+ - 🔗 **Hỗ trợ URL YouTube** trực tiếp
15
+ - 📱 **Metadata phong phú**: tác giả, lượt xem, mô tả, ngày upload, v.v.
16
+ - 🔄 **Video liên quan**: Tìm kiếm video liên quan cho một video cụ thể
17
+ - 🎵 **Mix Playlist**: Hỗ trợ xử lý YouTube Mix playlists (RD)
18
+ - ⚡ **Không streaming**: Chỉ trả về metadata, không tạo stream
19
+
20
+ ## 🚀 Cài Đặt
21
+
22
+ ```bash
23
+ npm install youtube-sr
24
+ ```
25
+
26
+ ## 📖 Cách Sử Dụng
27
+
28
+ ### Khởi Tạo Plugin
29
+
30
+ ```javascript
31
+ const { YTSRPlugin } = require("ziplayer/plugins");
32
+ const plugin = new YTSRPlugin();
33
+ ```
34
+
35
+ ### Tìm Kiếm Video Cơ Bản
36
+
37
+ ```javascript
38
+ // Tìm kiếm video đơn giản
39
+ const result = await plugin.search("Never Gonna Give You Up", "user123");
40
+ console.log(`Tìm thấy ${result.tracks.length} video`);
41
+
42
+ result.tracks.forEach((track) => {
43
+ console.log(`${track.title} - ${track.metadata?.author}`);
44
+ console.log(`URL: ${track.url}`);
45
+ console.log(`Thời lượng: ${track.duration}s`);
46
+ });
47
+ ```
48
+
49
+ ### Tìm Kiếm Với Tùy Chọn Nâng Cao
50
+
51
+ ```javascript
52
+ // Tìm kiếm với các filter nâng cao
53
+ const advancedResult = await plugin.search("chill music", "user123", {
54
+ limit: 10, // Số lượng kết quả tối đa
55
+ duration: "medium", // Thời lượng: short, medium, long, all
56
+ sortBy: "viewCount", // Sắp xếp: relevance, uploadDate, viewCount, rating
57
+ uploadDate: "month", // Ngày upload: hour, today, week, month, year, all
58
+ type: "video", // Loại: video, playlist, channel, all
59
+ });
60
+ ```
61
+
62
+ ### Tìm Kiếm Playlist
63
+
64
+ ```javascript
65
+ // Tìm kiếm playlist
66
+ const playlistResult = await plugin.searchPlaylist("lofi hip hop", "user123", 5);
67
+ playlistResult.tracks.forEach((track) => {
68
+ console.log(`Playlist: ${track.title}`);
69
+ console.log(`Channel: ${track.metadata?.author}`);
70
+ console.log(`Số video: ${track.metadata?.videoCount}`);
71
+ });
72
+ ```
73
+
74
+ ### Tìm Kiếm Channel
75
+
76
+ ```javascript
77
+ // Tìm kiếm channel
78
+ const channelResult = await plugin.searchChannel("PewDiePie", "user123", 3);
79
+ channelResult.tracks.forEach((track) => {
80
+ console.log(`Channel: ${track.title}`);
81
+ console.log(`Subscribers: ${track.metadata?.subscriberCount}`);
82
+ console.log(`URL: ${track.url}`);
83
+ });
84
+ ```
85
+
86
+ ### Tìm Kiếm Tất Cả Loại
87
+
88
+ ```javascript
89
+ // Tìm kiếm tất cả loại (video, playlist, channel)
90
+ const allResult = await plugin.search("music", "user123", {
91
+ type: "all",
92
+ limit: 15,
93
+ });
94
+
95
+ allResult.tracks.forEach((track) => {
96
+ const type = track.metadata?.type || "video";
97
+ console.log(`[${type.toUpperCase()}] ${track.title}`);
98
+ });
99
+ ```
100
+
101
+ ### Xử Lý URL YouTube
102
+
103
+ ```javascript
104
+ // Xử lý URL YouTube trực tiếp
105
+ const urlResult = await plugin.search("https://www.youtube.com/watch?v=dQw4w9WgXcQ", "user123");
106
+ if (urlResult.tracks.length > 0) {
107
+ const track = urlResult.tracks[0];
108
+ console.log(`Video: ${track.title}`);
109
+ console.log(`Tác giả: ${track.metadata?.author}`);
110
+ }
111
+ ```
112
+
113
+ ### Lấy Video Theo ID
114
+
115
+ ```javascript
116
+ // Lấy video theo ID cụ thể
117
+ const video = await plugin.getVideoById("dQw4w9WgXcQ", "user123");
118
+ if (video) {
119
+ console.log(`Video: ${video.title}`);
120
+ console.log(`Tác giả: ${video.metadata?.author}`);
121
+ console.log(`URL: ${video.url}`);
122
+ }
123
+ ```
124
+
125
+ ### Lấy Video Liên Quan
126
+
127
+ ```javascript
128
+ // Lấy video liên quan cho một video cụ thể
129
+ const relatedTracks = await plugin.getRelatedTracks("https://www.youtube.com/watch?v=dQw4w9WgXcQ", {
130
+ limit: 5, // Số lượng video liên quan tối đa
131
+ offset: 0, // Bỏ qua N video đầu tiên
132
+ history: [currentTrack], // Loại trừ các video đã phát
133
+ });
134
+
135
+ relatedTracks.forEach((track, index) => {
136
+ console.log(`${index + 1}. ${track.title} - ${track.metadata?.author}`);
137
+ });
138
+ ```
139
+
140
+ ### Xử Lý Mix Playlist (RD)
141
+
142
+ ```javascript
143
+ // Xử lý YouTube Mix playlist (RD)
144
+ const mixResult = await plugin.handleMixPlaylist(
145
+ "https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=RDMWGnHCaqxdU&start_radio=1",
146
+ "user123",
147
+ 10, // Số lượng track tối đa
148
+ );
149
+
150
+ console.log(`Mix playlist: ${mixResult.playlist?.name}`);
151
+ console.log(`Tìm thấy ${mixResult.tracks.length} track trong Mix`);
152
+
153
+ mixResult.tracks.forEach((track, index) => {
154
+ console.log(`${index + 1}. ${track.title} - ${track.metadata?.author}`);
155
+ });
156
+ ```
157
+
158
+ ## 📋 API Reference
159
+
160
+ ### `search(query, requestedBy, options?)`
161
+
162
+ Tìm kiếm nội dung trên YouTube với các tùy chọn nâng cao.
163
+
164
+ **Tham số:**
165
+
166
+ - `query` (string): Query tìm kiếm hoặc URL YouTube
167
+ - `requestedBy` (string): ID của user yêu cầu tìm kiếm
168
+ - `options` (object, tùy chọn):
169
+ - `limit` (number): Số lượng kết quả tối đa (mặc định: 10)
170
+ - `type` (string): Loại tìm kiếm - "video", "playlist", "channel", "all" (mặc định: "video")
171
+ - `duration` (string): Lọc theo thời lượng - "short", "medium", "long", "all" (mặc định: "all")
172
+ - `sortBy` (string): Sắp xếp - "relevance", "uploadDate", "viewCount", "rating" (mặc định: "relevance")
173
+ - `uploadDate` (string): Lọc theo ngày upload - "hour", "today", "week", "month", "year", "all" (mặc định: "all")
174
+
175
+ **Trả về:** `Promise<SearchResult>`
176
+
177
+ ### `searchPlaylist(query, requestedBy, limit?)`
178
+
179
+ Tìm kiếm playlist trên YouTube.
180
+
181
+ **Tham số:**
182
+
183
+ - `query` (string): Query tìm kiếm playlist
184
+ - `requestedBy` (string): ID của user yêu cầu
185
+ - `limit` (number, tùy chọn): Số lượng playlist tối đa (mặc định: 5)
186
+
187
+ **Trả về:** `Promise<SearchResult>`
188
+
189
+ ### `searchChannel(query, requestedBy, limit?)`
190
+
191
+ Tìm kiếm channel trên YouTube.
192
+
193
+ **Tham số:**
194
+
195
+ - `query` (string): Query tìm kiếm channel
196
+ - `requestedBy` (string): ID của user yêu cầu
197
+ - `limit` (number, tùy chọn): Số lượng channel tối đa (mặc định: 5)
198
+
199
+ **Trả về:** `Promise<SearchResult>`
200
+
201
+ ### `getVideoById(videoId, requestedBy)`
202
+
203
+ Lấy thông tin video theo ID cụ thể.
204
+
205
+ **Tham số:**
206
+
207
+ - `videoId` (string): ID của video YouTube
208
+ - `requestedBy` (string): ID của user yêu cầu
209
+
210
+ **Trả về:** `Promise<Track | null>`
211
+
212
+ ### `getRelatedTracks(trackURL, opts?)`
213
+
214
+ Lấy các video liên quan cho một video YouTube cụ thể.
215
+
216
+ **Tham số:**
217
+
218
+ - `trackURL` (string): URL của video YouTube để lấy video liên quan
219
+ - `opts` (object, tùy chọn):
220
+ - `limit` (number): Số lượng video liên quan tối đa (mặc định: 5)
221
+ - `offset` (number): Số lượng video bỏ qua từ đầu (mặc định: 0)
222
+ - `history` (Track[]): Mảng các track để loại trừ khỏi kết quả
223
+
224
+ **Trả về:** `Promise<Track[]>`
225
+
226
+ ### `handleMixPlaylist(mixUrl, requestedBy, limit?)`
227
+
228
+ Xử lý YouTube Mix playlist (RD) và tạo danh sách các video liên quan.
229
+
230
+ **Tham số:**
231
+
232
+ - `mixUrl` (string): URL của playlist Mix YouTube
233
+ - `requestedBy` (string): ID của user yêu cầu
234
+ - `limit` (number, tùy chọn): Số lượng track tối đa (mặc định: 10)
235
+
236
+ **Trả về:** `Promise<SearchResult>`
237
+
238
+ ### `canHandle(query)`
239
+
240
+ Kiểm tra xem plugin có thể xử lý query này không.
241
+
242
+ **Tham số:**
243
+
244
+ - `query` (string): Query để kiểm tra
245
+
246
+ **Trả về:** `boolean`
247
+
248
+ ### `validate(url)`
249
+
250
+ Xác thực URL YouTube.
251
+
252
+ **Tham số:**
253
+
254
+ - `url` (string): URL để xác thực
255
+
256
+ **Trả về:** `boolean`
257
+
258
+ ## ⚠️ Lưu Ý Quan Trọng
259
+
260
+ - **KHÔNG hỗ trợ streaming**: Plugin này chỉ dành cho tìm kiếm metadata, không tạo stream audio
261
+ - **KHÔNG hỗ trợ fallback**: Không có phương thức fallback streaming
262
+ - **Chỉ metadata**: Trả về thông tin về video/playlist/channel, không phải audio stream
263
+ - **Sử dụng với plugin khác**: Có thể kết hợp với YouTubePlugin để có cả tìm kiếm nâng cao và streaming
264
+
265
+ ## 🔧 Tích Hợp Với Plugin Khác
266
+
267
+ ```javascript
268
+ const { YTSRPlugin, YouTubePlugin } = require("ziplayer/plugins");
269
+
270
+ // Sử dụng YTSRPlugin để tìm kiếm nâng cao
271
+ const ytsrPlugin = new YTSRPlugin();
272
+ const searchResult = await ytsrPlugin.search("music", "user123", {
273
+ duration: "medium",
274
+ sortBy: "viewCount",
275
+ });
276
+
277
+ // Lấy video liên quan
278
+ const relatedTracks = await ytsrPlugin.getRelatedTracks(searchResult.tracks[0].url, {
279
+ limit: 3,
280
+ history: searchResult.tracks,
281
+ });
282
+
283
+ // Sử dụng YouTubePlugin để tạo stream
284
+ const youtubePlugin = new YouTubePlugin();
285
+ const stream = await youtubePlugin.getStream(searchResult.tracks[0]);
286
+ ```
287
+
288
+ ## 🧪 Testing
289
+
290
+ ```bash
291
+ # Chạy test cho YTSRPlugin
292
+ npm test tests/plugins/ytsrplugin.test.js
293
+ ```
294
+
295
+ ## 📝 Ví Dụ Hoàn Chỉnh
296
+
297
+ Xem file `examples/ytsr-example.js` để có ví dụ chi tiết về cách sử dụng plugin.
298
+
299
+ ## 🤝 Đóng Góp
300
+
301
+ Nếu bạn muốn đóng góp vào plugin này, vui lòng:
302
+
303
+ 1. Fork repository
304
+ 2. Tạo branch mới cho feature
305
+ 3. Commit changes
306
+ 4. Tạo Pull Request
307
+
308
+ ## 📄 License
309
+
310
+ MIT License - xem file LICENSE để biết thêm chi tiết.
@@ -1,21 +1,170 @@
1
1
  import { BasePlugin, Track, SearchResult, StreamInfo } from "ziplayer";
2
+ /**
3
+ * A plugin for handling SoundCloud audio content including tracks, playlists, and search functionality.
4
+ *
5
+ * This plugin provides comprehensive support for:
6
+ * - SoundCloud track URLs (soundcloud.com)
7
+ * - SoundCloud playlist URLs
8
+ * - SoundCloud search queries
9
+ * - Audio stream extraction from SoundCloud tracks
10
+ * - Related track recommendations
11
+ *
12
+ * @example
13
+ *
14
+ * const soundcloudPlugin = new SoundCloudPlugin();
15
+ *
16
+ * // Add to PlayerManager
17
+ * const manager = new PlayerManager({
18
+ * plugins: [soundcloudPlugin]
19
+ * });
20
+ *
21
+ * // Search for tracks
22
+ * const result = await soundcloudPlugin.search("chill music", "user123");
23
+ *
24
+ * // Get audio stream
25
+ * const stream = await soundcloudPlugin.getStream(result.tracks[0]);
26
+ *
27
+ * @since 1.0.0
28
+ */
2
29
  export declare class SoundCloudPlugin extends BasePlugin {
3
30
  name: string;
4
31
  version: string;
5
32
  private client;
6
33
  private ready;
34
+ /**
35
+ * Creates a new SoundCloudPlugin instance.
36
+ *
37
+ * The plugin will automatically initialize the SoundCloud client for track
38
+ * and playlist operations. Initialization is asynchronous and handled internally.
39
+ *
40
+ * @example
41
+ * const plugin = new SoundCloudPlugin();
42
+ * // Plugin is ready to use after initialization completes
43
+ */
7
44
  constructor();
8
45
  private init;
46
+ /**
47
+ * Determines if this plugin can handle the given query.
48
+ *
49
+ * @param query - The search query or URL to check
50
+ * @returns `true` if the plugin can handle the query, `false` otherwise
51
+ *
52
+ * @example
53
+ * plugin.canHandle("https://soundcloud.com/artist/track"); // true
54
+ * plugin.canHandle("chill music"); // true
55
+ * plugin.canHandle("spotify:track:123"); // false
56
+ */
9
57
  canHandle(query: string): boolean;
58
+ /**
59
+ * Validates if a URL is a valid SoundCloud URL.
60
+ *
61
+ * @param url - The URL to validate
62
+ * @returns `true` if the URL is a valid SoundCloud URL, `false` otherwise
63
+ *
64
+ * @example
65
+ * plugin.validate("https://soundcloud.com/artist/track"); // true
66
+ * plugin.validate("https://www.soundcloud.com/artist/track"); // true
67
+ * plugin.validate("https://youtube.com/watch?v=123"); // false
68
+ */
10
69
  validate(url: string): boolean;
70
+ /**
71
+ * Searches for SoundCloud content based on the given query.
72
+ *
73
+ * This method handles both URL-based queries (direct track/playlist links) and
74
+ * text-based search queries. For URLs, it will extract track or playlist information.
75
+ * For text queries, it will perform a SoundCloud search and return up to 10 results.
76
+ *
77
+ * @param query - The search query (URL or text)
78
+ * @param requestedBy - The user ID who requested the search
79
+ * @returns A SearchResult containing tracks and optional playlist information
80
+ *
81
+ * @example
82
+ * // Search by URL
83
+ * const result = await plugin.search("https://soundcloud.com/artist/track", "user123");
84
+ *
85
+ * // Search by text
86
+ * const searchResult = await plugin.search("chill music", "user123");
87
+ * console.log(searchResult.tracks); // Array of Track objects
88
+ */
11
89
  search(query: string, requestedBy: string): Promise<SearchResult>;
90
+ /**
91
+ * Retrieves the audio stream for a SoundCloud track.
92
+ *
93
+ * This method downloads the audio stream from SoundCloud using the track's URL.
94
+ * It handles the SoundCloud-specific download process and returns the stream
95
+ * in a format compatible with the player.
96
+ *
97
+ * @param track - The Track object to get the stream for
98
+ * @returns A StreamInfo object containing the audio stream and metadata
99
+ * @throws {Error} If the track URL is invalid or stream download fails
100
+ *
101
+ * @example
102
+ * const track = { id: "123", title: "Track Title", url: "https://soundcloud.com/artist/track", ... };
103
+ * const streamInfo = await plugin.getStream(track);
104
+ * console.log(streamInfo.type); // "arbitrary"
105
+ * console.log(streamInfo.stream); // Readable stream
106
+ */
12
107
  getStream(track: Track): Promise<StreamInfo>;
108
+ /**
109
+ * Gets related tracks for a given SoundCloud track.
110
+ *
111
+ * This method fetches related tracks from SoundCloud's recommendation system
112
+ * based on the provided track URL or ID. It can filter out tracks that are
113
+ * already in the history to avoid duplicates.
114
+ *
115
+ * @param trackURL - The SoundCloud track URL or ID to get related tracks for
116
+ * @param opts - Options for filtering and limiting results
117
+ * @param opts.limit - Maximum number of related tracks to return (default: 1)
118
+ * @param opts.offset - Number of tracks to skip from the beginning (default: 0)
119
+ * @param opts.history - Array of tracks to exclude from results
120
+ * @returns An array of related Track objects
121
+ *
122
+ * @example
123
+ * const related = await plugin.getRelatedTracks(
124
+ * "https://soundcloud.com/artist/track",
125
+ * { limit: 3, history: [currentTrack] }
126
+ * );
127
+ * console.log(`Found ${related.length} related tracks`);
128
+ */
13
129
  getRelatedTracks(trackURL: string | number, opts?: {
14
130
  limit?: number;
15
131
  offset?: number;
16
132
  history?: Track[];
17
133
  }): Promise<Track[]>;
134
+ /**
135
+ * Provides a fallback stream by searching for the track title.
136
+ *
137
+ * This method is used when the primary stream extraction fails. It performs
138
+ * a search using the track's title and attempts to get a stream from the
139
+ * first search result.
140
+ *
141
+ * @param track - The Track object to get a fallback stream for
142
+ * @returns A StreamInfo object containing the fallback audio stream
143
+ * @throws {Error} If no fallback track is found or stream extraction fails
144
+ *
145
+ * @example
146
+ * try {
147
+ * const stream = await plugin.getStream(track);
148
+ * } catch (error) {
149
+ * // Try fallback
150
+ * const fallbackStream = await plugin.getFallback(track);
151
+ * }
152
+ */
18
153
  getFallback(track: Track): Promise<StreamInfo>;
154
+ /**
155
+ * Extracts tracks from a SoundCloud playlist URL.
156
+ *
157
+ * @param url - The SoundCloud playlist URL
158
+ * @param requestedBy - The user ID who requested the extraction
159
+ * @returns An array of Track objects from the playlist
160
+ *
161
+ * @example
162
+ * const tracks = await plugin.extractPlaylist(
163
+ * "https://soundcloud.com/artist/sets/playlist-name",
164
+ * "user123"
165
+ * );
166
+ * console.log(`Found ${tracks.length} tracks in playlist`);
167
+ */
19
168
  extractPlaylist(url: string, requestedBy: string): Promise<Track[]>;
20
169
  }
21
170
  //# sourceMappingURL=SoundCloudPlugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SoundCloudPlugin.d.ts","sourceRoot":"","sources":["../src/SoundCloudPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAgBvE,qBAAa,gBAAiB,SAAQ,UAAU;IAC/C,IAAI,SAAgB;IACpB,OAAO,SAAW;IAClB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,KAAK,CAAgB;;YAOf,IAAI;IAKlB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAgBjC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIxB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAgFjE,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;IAmB5C,gBAAgB,CACrB,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAA;KAAO,GAC/D,OAAO,CAAC,KAAK,EAAE,CAAC;IAiCb,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;IAS9C,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;CAsBzE"}
1
+ {"version":3,"file":"SoundCloudPlugin.d.ts","sourceRoot":"","sources":["../src/SoundCloudPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAgBvE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,gBAAiB,SAAQ,UAAU;IAC/C,IAAI,SAAgB;IACpB,OAAO,SAAW;IAClB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,KAAK,CAAgB;IAE7B;;;;;;;;;OASG;;YAMW,IAAI;IAKlB;;;;;;;;;;OAUG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAgBjC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B;;;;;;;;;;;;;;;;;;OAkBG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAgFvE;;;;;;;;;;;;;;;;OAgBG;IACG,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;IAmBlD;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,gBAAgB,CACrB,QAAQ,EAAE,MAAM,GAAG,MAAM,EACzB,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAA;KAAO,GAC/D,OAAO,CAAC,KAAK,EAAE,CAAC;IAiCnB;;;;;;;;;;;;;;;;;;OAkBG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;IASpD;;;;;;;;;;;;;OAaG;IACG,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;CAsBzE"}
@@ -15,7 +15,44 @@ function isValidSoundCloudHost(maybeUrl) {
15
15
  return false;
16
16
  }
17
17
  }
18
+ /**
19
+ * A plugin for handling SoundCloud audio content including tracks, playlists, and search functionality.
20
+ *
21
+ * This plugin provides comprehensive support for:
22
+ * - SoundCloud track URLs (soundcloud.com)
23
+ * - SoundCloud playlist URLs
24
+ * - SoundCloud search queries
25
+ * - Audio stream extraction from SoundCloud tracks
26
+ * - Related track recommendations
27
+ *
28
+ * @example
29
+ *
30
+ * const soundcloudPlugin = new SoundCloudPlugin();
31
+ *
32
+ * // Add to PlayerManager
33
+ * const manager = new PlayerManager({
34
+ * plugins: [soundcloudPlugin]
35
+ * });
36
+ *
37
+ * // Search for tracks
38
+ * const result = await soundcloudPlugin.search("chill music", "user123");
39
+ *
40
+ * // Get audio stream
41
+ * const stream = await soundcloudPlugin.getStream(result.tracks[0]);
42
+ *
43
+ * @since 1.0.0
44
+ */
18
45
  class SoundCloudPlugin extends ziplayer_1.BasePlugin {
46
+ /**
47
+ * Creates a new SoundCloudPlugin instance.
48
+ *
49
+ * The plugin will automatically initialize the SoundCloud client for track
50
+ * and playlist operations. Initialization is asynchronous and handled internally.
51
+ *
52
+ * @example
53
+ * const plugin = new SoundCloudPlugin();
54
+ * // Plugin is ready to use after initialization completes
55
+ */
19
56
  constructor() {
20
57
  super();
21
58
  this.name = "soundcloud";
@@ -26,6 +63,17 @@ class SoundCloudPlugin extends ziplayer_1.BasePlugin {
26
63
  this.client = new SoundCloud({ init: false });
27
64
  await this.client.init();
28
65
  }
66
+ /**
67
+ * Determines if this plugin can handle the given query.
68
+ *
69
+ * @param query - The search query or URL to check
70
+ * @returns `true` if the plugin can handle the query, `false` otherwise
71
+ *
72
+ * @example
73
+ * plugin.canHandle("https://soundcloud.com/artist/track"); // true
74
+ * plugin.canHandle("chill music"); // true
75
+ * plugin.canHandle("spotify:track:123"); // false
76
+ */
29
77
  canHandle(query) {
30
78
  const q = (query || "").trim().toLowerCase();
31
79
  const isUrl = q.startsWith("http://") || q.startsWith("https://");
@@ -42,9 +90,39 @@ class SoundCloudPlugin extends ziplayer_1.BasePlugin {
42
90
  // Treat remaining non-URL free text as searchable
43
91
  return true;
44
92
  }
93
+ /**
94
+ * Validates if a URL is a valid SoundCloud URL.
95
+ *
96
+ * @param url - The URL to validate
97
+ * @returns `true` if the URL is a valid SoundCloud URL, `false` otherwise
98
+ *
99
+ * @example
100
+ * plugin.validate("https://soundcloud.com/artist/track"); // true
101
+ * plugin.validate("https://www.soundcloud.com/artist/track"); // true
102
+ * plugin.validate("https://youtube.com/watch?v=123"); // false
103
+ */
45
104
  validate(url) {
46
105
  return isValidSoundCloudHost(url);
47
106
  }
107
+ /**
108
+ * Searches for SoundCloud content based on the given query.
109
+ *
110
+ * This method handles both URL-based queries (direct track/playlist links) and
111
+ * text-based search queries. For URLs, it will extract track or playlist information.
112
+ * For text queries, it will perform a SoundCloud search and return up to 10 results.
113
+ *
114
+ * @param query - The search query (URL or text)
115
+ * @param requestedBy - The user ID who requested the search
116
+ * @returns A SearchResult containing tracks and optional playlist information
117
+ *
118
+ * @example
119
+ * // Search by URL
120
+ * const result = await plugin.search("https://soundcloud.com/artist/track", "user123");
121
+ *
122
+ * // Search by text
123
+ * const searchResult = await plugin.search("chill music", "user123");
124
+ * console.log(searchResult.tracks); // Array of Track objects
125
+ */
48
126
  async search(query, requestedBy) {
49
127
  await this.ready;
50
128
  // If the query is a URL but not a SoundCloud URL, do not handle it here
@@ -122,6 +200,23 @@ class SoundCloudPlugin extends ziplayer_1.BasePlugin {
122
200
  throw new Error(`SoundCloud search failed: ${error?.message}`);
123
201
  }
124
202
  }
203
+ /**
204
+ * Retrieves the audio stream for a SoundCloud track.
205
+ *
206
+ * This method downloads the audio stream from SoundCloud using the track's URL.
207
+ * It handles the SoundCloud-specific download process and returns the stream
208
+ * in a format compatible with the player.
209
+ *
210
+ * @param track - The Track object to get the stream for
211
+ * @returns A StreamInfo object containing the audio stream and metadata
212
+ * @throws {Error} If the track URL is invalid or stream download fails
213
+ *
214
+ * @example
215
+ * const track = { id: "123", title: "Track Title", url: "https://soundcloud.com/artist/track", ... };
216
+ * const streamInfo = await plugin.getStream(track);
217
+ * console.log(streamInfo.type); // "arbitrary"
218
+ * console.log(streamInfo.stream); // Readable stream
219
+ */
125
220
  async getStream(track) {
126
221
  await this.ready;
127
222
  try {
@@ -139,6 +234,27 @@ class SoundCloudPlugin extends ziplayer_1.BasePlugin {
139
234
  throw new Error(`Failed to get SoundCloud stream: ${error.message}`);
140
235
  }
141
236
  }
237
+ /**
238
+ * Gets related tracks for a given SoundCloud track.
239
+ *
240
+ * This method fetches related tracks from SoundCloud's recommendation system
241
+ * based on the provided track URL or ID. It can filter out tracks that are
242
+ * already in the history to avoid duplicates.
243
+ *
244
+ * @param trackURL - The SoundCloud track URL or ID to get related tracks for
245
+ * @param opts - Options for filtering and limiting results
246
+ * @param opts.limit - Maximum number of related tracks to return (default: 1)
247
+ * @param opts.offset - Number of tracks to skip from the beginning (default: 0)
248
+ * @param opts.history - Array of tracks to exclude from results
249
+ * @returns An array of related Track objects
250
+ *
251
+ * @example
252
+ * const related = await plugin.getRelatedTracks(
253
+ * "https://soundcloud.com/artist/track",
254
+ * { limit: 3, history: [currentTrack] }
255
+ * );
256
+ * console.log(`Found ${related.length} related tracks`);
257
+ */
142
258
  async getRelatedTracks(trackURL, opts = {}) {
143
259
  await this.ready;
144
260
  try {
@@ -169,6 +285,25 @@ class SoundCloudPlugin extends ziplayer_1.BasePlugin {
169
285
  return [];
170
286
  }
171
287
  }
288
+ /**
289
+ * Provides a fallback stream by searching for the track title.
290
+ *
291
+ * This method is used when the primary stream extraction fails. It performs
292
+ * a search using the track's title and attempts to get a stream from the
293
+ * first search result.
294
+ *
295
+ * @param track - The Track object to get a fallback stream for
296
+ * @returns A StreamInfo object containing the fallback audio stream
297
+ * @throws {Error} If no fallback track is found or stream extraction fails
298
+ *
299
+ * @example
300
+ * try {
301
+ * const stream = await plugin.getStream(track);
302
+ * } catch (error) {
303
+ * // Try fallback
304
+ * const fallbackStream = await plugin.getFallback(track);
305
+ * }
306
+ */
172
307
  async getFallback(track) {
173
308
  const trackfall = await this.search(track.title, track.requestedBy);
174
309
  const fallbackTrack = trackfall.tracks?.[0];
@@ -177,6 +312,20 @@ class SoundCloudPlugin extends ziplayer_1.BasePlugin {
177
312
  }
178
313
  return await this.getStream(fallbackTrack);
179
314
  }
315
+ /**
316
+ * Extracts tracks from a SoundCloud playlist URL.
317
+ *
318
+ * @param url - The SoundCloud playlist URL
319
+ * @param requestedBy - The user ID who requested the extraction
320
+ * @returns An array of Track objects from the playlist
321
+ *
322
+ * @example
323
+ * const tracks = await plugin.extractPlaylist(
324
+ * "https://soundcloud.com/artist/sets/playlist-name",
325
+ * "user123"
326
+ * );
327
+ * console.log(`Found ${tracks.length} tracks in playlist`);
328
+ */
180
329
  async extractPlaylist(url, requestedBy) {
181
330
  await this.ready;
182
331
  try {