@ziplayer/plugin 0.1.51 → 0.2.1-dev-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.
@@ -3,24 +3,168 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_SABR_OPTIONS = void 0;
4
4
  exports.createSabrStream = createSabrStream;
5
5
  exports.createOutputStream = createOutputStream;
6
- exports.createStreamSink = createStreamSink;
6
+ exports.sanitizeFileName = sanitizeFileName;
7
+ exports.bytesToMB = bytesToMB;
7
8
  const fs_1 = require("fs");
8
9
  const path_1 = require("path");
9
10
  const os_1 = require("os");
11
+ const youtubei_js_1 = require("youtubei.js");
12
+ const sabr_stream_1 = require("googlevideo/sabr-stream");
13
+ const utils_1 = require("googlevideo/utils");
14
+ const bgutils_js_1 = require("bgutils-js");
15
+ const jsdom_1 = require("jsdom");
16
+ const stream_converter_1 = require("./stream-converter");
10
17
  /**
11
- * Creates a sabr stream for YouTube video download
18
+ * Generates a web PoToken for YouTube authentication
19
+ * This is required for accessing restricted video content
12
20
  */
13
- async function createSabrStream(videoId, options) {
21
+ async function generateWebPoToken(contentBinding) {
14
22
  try {
15
- // Dynamic import to avoid build-time errors
16
- const sabrModule = require("googlevideo/sabr-stream");
17
- const createSabrStreamImpl = sabrModule.createSabrStream;
18
- const streamResults = await createSabrStreamImpl(videoId, options);
19
- return { streamResults };
23
+ const requestKey = "O43z0dpjhgX20SCx4KAo";
24
+ if (!contentBinding)
25
+ throw new Error("Could not get visitor data");
26
+ const dom = new jsdom_1.JSDOM();
27
+ Object.assign(globalThis, {
28
+ window: dom.window,
29
+ document: dom.window.document,
30
+ });
31
+ const bgConfig = {
32
+ fetch: (input, init) => fetch(input, init),
33
+ globalObj: globalThis,
34
+ identifier: contentBinding,
35
+ requestKey,
36
+ };
37
+ const bgChallenge = await bgutils_js_1.BG.Challenge.create(bgConfig);
38
+ if (!bgChallenge)
39
+ throw new Error("Could not get challenge");
40
+ const interpreterJavascript = bgChallenge.interpreterJavascript.privateDoNotAccessOrElseSafeScriptWrappedValue;
41
+ if (interpreterJavascript) {
42
+ new Function(interpreterJavascript)();
43
+ }
44
+ else
45
+ throw new Error("Could not load VM");
46
+ const poTokenResult = await bgutils_js_1.BG.PoToken.generate({
47
+ program: bgChallenge.program,
48
+ globalName: bgChallenge.globalName,
49
+ bgConfig,
50
+ });
51
+ const placeholderPoToken = bgutils_js_1.BG.PoToken.generatePlaceholder(contentBinding);
52
+ return {
53
+ visitorData: contentBinding,
54
+ placeholderPoToken,
55
+ poToken: poTokenResult.poToken,
56
+ };
20
57
  }
21
58
  catch (error) {
22
- // Fallback implementation if sabr download is not available
23
- throw new Error(`Sabr download not available: ${error}`);
59
+ console.warn("PoToken generation failed, continuing without it:", error);
60
+ return {
61
+ visitorData: contentBinding,
62
+ placeholderPoToken: "",
63
+ poToken: "",
64
+ };
65
+ }
66
+ }
67
+ /**
68
+ * Makes a proper player request to YouTube API
69
+ */
70
+ async function makePlayerRequest(innertube, videoId, reloadPlaybackContext) {
71
+ const watchEndpoint = new youtubei_js_1.YTNodes.NavigationEndpoint({
72
+ watchEndpoint: { videoId },
73
+ });
74
+ const extraArgs = {
75
+ playbackContext: {
76
+ adPlaybackContext: { pyv: true },
77
+ contentPlaybackContext: {
78
+ vis: 0,
79
+ splay: false,
80
+ lactMilliseconds: "-1",
81
+ signatureTimestamp: innertube.session.player?.signature_timestamp,
82
+ },
83
+ },
84
+ contentCheckOk: true,
85
+ racyCheckOk: true,
86
+ };
87
+ if (reloadPlaybackContext) {
88
+ extraArgs.playbackContext.reloadPlaybackContext = reloadPlaybackContext;
89
+ }
90
+ return watchEndpoint.call(innertube.actions, {
91
+ ...extraArgs,
92
+ parse: true,
93
+ });
94
+ }
95
+ /**
96
+ * YouTube VM shim
97
+ * This allows the SABR stream to execute YouTube's custom JavaScript for deciphering signatures and generating tokens
98
+ */
99
+ youtubei_js_1.Platform.shim.eval = async (data, env) => {
100
+ const properties = [];
101
+ if (env.n)
102
+ properties.push(`n: exportedVars.nFunction("${env.n}")`);
103
+ if (env.sig)
104
+ properties.push(`sig: exportedVars.sigFunction("${env.sig}")`);
105
+ const code = `${data.output}\nreturn { ${properties.join(", ")} }`;
106
+ return new Function(code)();
107
+ };
108
+ /**
109
+ * Creates a SABR audio stream for YouTube video download
110
+ * This provides better quality and more reliable streaming than standard methods
111
+ */
112
+ async function createSabrStream(videoId, innertube, options) {
113
+ try {
114
+ // Generate PoToken for authentication
115
+ const webPo = await generateWebPoToken(videoId);
116
+ // Make initial player request
117
+ const player = await makePlayerRequest(innertube, videoId);
118
+ const title = player.video_details?.title || "unknown";
119
+ const serverAbrStreamingUrl = await innertube.session.player?.decipher(player.streaming_data?.server_abr_streaming_url);
120
+ const ustreamerConfig = player.player_config?.media_common_config.media_ustreamer_request_config?.video_playback_ustreamer_config;
121
+ if (!serverAbrStreamingUrl || !ustreamerConfig) {
122
+ throw new Error("Missing SABR streaming config");
123
+ }
124
+ const sabrFormats = player.streaming_data?.adaptive_formats.map((f) => (0, utils_1.buildSabrFormat)(f)) || [];
125
+ const sabr = new sabr_stream_1.SabrStream({
126
+ formats: sabrFormats,
127
+ serverAbrStreamingUrl,
128
+ videoPlaybackUstreamerConfig: ustreamerConfig,
129
+ poToken: webPo.poToken,
130
+ clientInfo: {
131
+ clientName: parseInt(youtubei_js_1.Constants.CLIENT_NAME_IDS[innertube.session.context.client.clientName]),
132
+ clientVersion: innertube.session.context.client.clientVersion,
133
+ },
134
+ });
135
+ // Handle player response reload events
136
+ sabr.on("reloadPlayerResponse", async (ctx) => {
137
+ try {
138
+ const pr = await makePlayerRequest(innertube, videoId, ctx);
139
+ const url = await innertube.session.player?.decipher(pr.streaming_data?.server_abr_streaming_url);
140
+ const config = pr.player_config?.media_common_config.media_ustreamer_request_config?.video_playback_ustreamer_config;
141
+ if (url && config) {
142
+ sabr.setStreamingURL(url);
143
+ sabr.setUstreamerConfig(config);
144
+ }
145
+ }
146
+ catch (error) {
147
+ console.error("Failed to reload player response:", error);
148
+ }
149
+ });
150
+ // Start the stream with audio preference
151
+ const { audioStream, selectedFormats } = await sabr.start({
152
+ // audioQuality: options?.audioQuality || "high",
153
+ });
154
+ // Convert Web Stream to Node.js Readable stream
155
+ const nodeStream = (0, stream_converter_1.webStreamToNodeStream)(audioStream);
156
+ return {
157
+ title,
158
+ stream: nodeStream,
159
+ format: {
160
+ mimeType: selectedFormats.audioFormat.mimeType || "audio/webm",
161
+ itag: selectedFormats.audioFormat.itag || 0,
162
+ contentLength: selectedFormats.audioFormat.contentLength || 0,
163
+ },
164
+ };
165
+ }
166
+ catch (error) {
167
+ throw new Error(`SABR stream creation failed: ${error instanceof Error ? error.message : String(error)}`);
24
168
  }
25
169
  }
26
170
  /**
@@ -38,23 +182,16 @@ function createOutputStream(videoTitle, mimeType) {
38
182
  };
39
183
  }
40
184
  /**
41
- * Creates a stream sink for piping data with progress tracking
185
+ * Sanitizes a filename by removing invalid characters
42
186
  */
43
- function createStreamSink(format, outputStream, progressBar) {
44
- return new WritableStream({
45
- start() {
46
- // Initialize progress tracking
47
- },
48
- write(chunk) {
49
- outputStream.write(chunk);
50
- if (progressBar) {
51
- progressBar.increment(chunk.length);
52
- }
53
- },
54
- close() {
55
- outputStream.end();
56
- },
57
- });
187
+ function sanitizeFileName(name) {
188
+ return name.replace(/[^\w\d]+/g, "_").slice(0, 128);
189
+ }
190
+ /**
191
+ * Converts bytes to megabytes
192
+ */
193
+ function bytesToMB(bytes) {
194
+ return (bytes / 1024 / 1024).toFixed(2);
58
195
  }
59
196
  /**
60
197
  * Gets file extension from MIME type
@@ -77,7 +214,7 @@ exports.DEFAULT_SABR_OPTIONS = {
77
214
  preferWebM: true,
78
215
  preferOpus: true,
79
216
  videoQuality: "720p",
80
- audioQuality: "AUDIO_QUALITY_MEDIUM",
217
+ audioQuality: "high",
81
218
  enabledTrackTypes: "VIDEO_AND_AUDIO",
82
219
  };
83
220
  //# sourceMappingURL=sabr-stream-factory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sabr-stream-factory.js","sourceRoot":"","sources":["../../src/utils/sabr-stream-factory.ts"],"names":[],"mappings":";;;AAkBA,4CAaC;AAKD,gDAYC;AAKD,4CAeC;AApED,2BAAuC;AACvC,+BAA4B;AAC5B,2BAA4B;AAa5B;;GAEG;AACI,KAAK,UAAU,gBAAgB,CAAC,OAAe,EAAE,OAA4B;IACnF,IAAI,CAAC;QACJ,4CAA4C;QAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,yBAAyB,CAAQ,CAAC;QAC7D,MAAM,oBAAoB,GAAG,UAAU,CAAC,gBAAgB,CAAC;QAEzD,MAAM,aAAa,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAEnE,OAAO,EAAE,aAAa,EAAE,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,4DAA4D;QAC5D,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;AACF,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAAC,UAAkB,EAAE,QAAgB;IACtE,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClF,MAAM,SAAS,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,GAAG,cAAc,IAAI,SAAS,EAAE,CAAC;IAClD,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,IAAA,WAAM,GAAE,EAAE,QAAQ,CAAC,CAAC;IAE1C,MAAM,MAAM,GAAG,IAAA,sBAAiB,EAAC,QAAQ,CAAC,CAAC;IAE3C,OAAO;QACN,MAAM;QACN,QAAQ;KACR,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,MAAW,EAAE,YAAmC,EAAE,WAAgB;IAClG,OAAO,IAAI,cAAc,CAAC;QACzB,KAAK;YACJ,+BAA+B;QAChC,CAAC;QACD,KAAK,CAAC,KAAK;YACV,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,WAAW,EAAE,CAAC;gBACjB,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACrC,CAAC;QACF,CAAC;QACD,KAAK;YACJ,YAAY,CAAC,GAAG,EAAE,CAAC;QACpB,CAAC;KACD,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,wBAAwB,CAAC,QAAgB;IACjD,MAAM,OAAO,GAA8B;QAC1C,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,KAAK;KAClB,CAAC;IAEF,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC;AACnC,CAAC;AAED;;GAEG;AACU,QAAA,oBAAoB,GAAwB;IACxD,UAAU,EAAE,IAAI;IAChB,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,MAAM;IACpB,YAAY,EAAE,sBAAsB;IACpC,iBAAiB,EAAE,iBAAiB;CACpC,CAAC"}
1
+ {"version":3,"file":"sabr-stream-factory.js","sourceRoot":"","sources":["../../src/utils/sabr-stream-factory.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,7 @@
1
1
  import { Readable } from "stream";
2
2
  /**
3
3
  * Converts a Web ReadableStream to a Node.js Readable stream
4
+ * with proper cleanup handling to prevent "Controller is already closed" errors
4
5
  */
5
6
  export declare function webStreamToNodeStream(webStream: ReadableStream): Readable;
6
- /**
7
- * Converts a Web ReadableStream to a Node.js Readable stream with progress tracking
8
- */
9
- export declare function webStreamToNodeStreamWithProgress(webStream: ReadableStream, progressCallback?: (bytesRead: number) => void): Readable;
10
7
  //# sourceMappingURL=stream-converter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-converter.d.ts","sourceRoot":"","sources":["../../src/utils/stream-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,cAAc,GAAG,QAAQ,CA8BzE;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAChD,SAAS,EAAE,cAAc,EACzB,gBAAgB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAC5C,QAAQ,CAmCV"}
1
+ {"version":3,"file":"stream-converter.d.ts","sourceRoot":"","sources":["../../src/utils/stream-converter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,cAAc,GAAG,QAAQ,CAuGzE"}
@@ -1,71 +1,103 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.webStreamToNodeStream = webStreamToNodeStream;
4
- exports.webStreamToNodeStreamWithProgress = webStreamToNodeStreamWithProgress;
5
4
  const stream_1 = require("stream");
6
5
  /**
7
6
  * Converts a Web ReadableStream to a Node.js Readable stream
7
+ * with proper cleanup handling to prevent "Controller is already closed" errors
8
8
  */
9
9
  function webStreamToNodeStream(webStream) {
10
+ let reader = null;
11
+ let pumpActive = true;
12
+ let abortController = null;
10
13
  const nodeStream = new stream_1.Readable({
11
14
  read() {
12
15
  // This will be handled by the Web Stream reader
13
16
  },
17
+ destroy(error, callback) {
18
+ // Gracefully stop the pump when stream is destroyed
19
+ pumpActive = false;
20
+ // Cancel reader if active
21
+ if (reader) {
22
+ try {
23
+ // reader.cancel() will abort the fetch
24
+ reader.cancel().catch(() => {
25
+ // Ignore cancel errors
26
+ });
27
+ reader = null;
28
+ }
29
+ catch { }
30
+ }
31
+ // Abort any pending operations
32
+ if (abortController) {
33
+ try {
34
+ abortController.abort();
35
+ }
36
+ catch { }
37
+ abortController = null;
38
+ }
39
+ callback(error);
40
+ },
14
41
  });
42
+ // Create abort controller for graceful shutdown
43
+ abortController = new AbortController();
15
44
  // Create a reader from the Web Stream
16
- const reader = webStream.getReader();
45
+ reader = webStream.getReader();
17
46
  // Read chunks and push to Node.js stream
18
47
  const pump = async () => {
19
48
  try {
20
- while (true) {
49
+ while (pumpActive && reader) {
21
50
  const { done, value } = await reader.read();
51
+ // Check if pump was stopped during read
52
+ if (!pumpActive || !reader) {
53
+ break;
54
+ }
22
55
  if (done) {
23
56
  nodeStream.push(null); // End the stream
24
57
  break;
25
58
  }
26
- nodeStream.push(Buffer.from(value));
59
+ if (value && pumpActive) {
60
+ nodeStream.push(Buffer.from(value));
61
+ }
27
62
  }
28
63
  }
29
64
  catch (error) {
30
- nodeStream.destroy(error);
31
- }
32
- };
33
- // Start pumping data
34
- pump();
35
- return nodeStream;
36
- }
37
- /**
38
- * Converts a Web ReadableStream to a Node.js Readable stream with progress tracking
39
- */
40
- function webStreamToNodeStreamWithProgress(webStream, progressCallback) {
41
- const nodeStream = new stream_1.Readable({
42
- read() {
43
- // This will be handled by the Web Stream reader
44
- },
45
- });
46
- let bytesRead = 0;
47
- const reader = webStream.getReader();
48
- const pump = async () => {
49
- try {
50
- while (true) {
51
- const { done, value } = await reader.read();
52
- if (done) {
53
- nodeStream.push(null); // End the stream
54
- break;
65
+ // Only destroy if pump is still active and stream exists
66
+ if (pumpActive) {
67
+ const errorMsg = error instanceof Error ? error.message : String(error);
68
+ // Ignore "Controller is already closed" and stream cancelled errors
69
+ if (errorMsg.includes("Controller is already closed") ||
70
+ errorMsg.includes("already been cancelled") ||
71
+ errorMsg.includes("stream closed") ||
72
+ errorMsg.includes("aborted")) {
73
+ // Stream was destroyed externally, just end cleanly
74
+ nodeStream.push(null);
55
75
  }
56
- const buffer = Buffer.from(value);
57
- nodeStream.push(buffer);
58
- bytesRead += buffer.length;
59
- if (progressCallback) {
60
- progressCallback(bytesRead);
76
+ else {
77
+ // Real error, report it
78
+ nodeStream.destroy(error);
61
79
  }
62
80
  }
63
81
  }
64
- catch (error) {
65
- nodeStream.destroy(error);
82
+ finally {
83
+ // Cleanup reader when pump ends
84
+ try {
85
+ if (reader) {
86
+ await reader.cancel();
87
+ reader = null;
88
+ }
89
+ }
90
+ catch { }
91
+ pumpActive = false;
66
92
  }
67
93
  };
68
- pump();
94
+ // Start pumping data
95
+ pump().catch((error) => {
96
+ // Catch any unhandled promise rejection
97
+ if (pumpActive) {
98
+ console.error("[stream-converter] Pump error:", error);
99
+ }
100
+ });
69
101
  return nodeStream;
70
102
  }
71
103
  //# sourceMappingURL=stream-converter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream-converter.js","sourceRoot":"","sources":["../../src/utils/stream-converter.ts"],"names":[],"mappings":";;AAKA,sDA8BC;AAKD,8EAsCC;AA9ED,mCAAkC;AAElC;;GAEG;AACH,SAAgB,qBAAqB,CAAC,SAAyB;IAC9D,MAAM,UAAU,GAAG,IAAI,iBAAQ,CAAC;QAC/B,IAAI;YACH,gDAAgD;QACjD,CAAC;KACD,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;IAErC,yCAAyC;IACzC,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACvB,IAAI,CAAC;YACJ,OAAO,IAAI,EAAE,CAAC;gBACb,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,IAAI,EAAE,CAAC;oBACV,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB;oBACxC,MAAM;gBACP,CAAC;gBACD,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YACrC,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,UAAU,CAAC,OAAO,CAAC,KAAc,CAAC,CAAC;QACpC,CAAC;IACF,CAAC,CAAC;IAEF,qBAAqB;IACrB,IAAI,EAAE,CAAC;IAEP,OAAO,UAAU,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAgB,iCAAiC,CAChD,SAAyB,EACzB,gBAA8C;IAE9C,MAAM,UAAU,GAAG,IAAI,iBAAQ,CAAC;QAC/B,IAAI;YACH,gDAAgD;QACjD,CAAC;KACD,CAAC,CAAC;IAEH,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;IAErC,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACvB,IAAI,CAAC;YACJ,OAAO,IAAI,EAAE,CAAC;gBACb,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,IAAI,EAAE,CAAC;oBACV,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB;oBACxC,MAAM;gBACP,CAAC;gBAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAClC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAExB,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC;gBAC3B,IAAI,gBAAgB,EAAE,CAAC;oBACtB,gBAAgB,CAAC,SAAS,CAAC,CAAC;gBAC7B,CAAC;YACF,CAAC;QACF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,UAAU,CAAC,OAAO,CAAC,KAAc,CAAC,CAAC;QACpC,CAAC;IACF,CAAC,CAAC;IAEF,IAAI,EAAE,CAAC;IAEP,OAAO,UAAU,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"stream-converter.js","sourceRoot":"","sources":["../../src/utils/stream-converter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,45 +1,46 @@
1
- {
2
- "name": "@ziplayer/plugin",
3
- "version": "0.1.51",
4
- "description": "A modular Discord voice player with plugin system",
5
- "keywords": [
6
- "ZiPlayer",
7
- "@ziplayer/plugin",
8
- "discord",
9
- "music",
10
- "player",
11
- "voice"
12
- ],
13
- "homepage": "https://player.ziji.world",
14
- "bugs": {
15
- "url": "https://github.com/ZiProject/ZiPlayer/issues"
16
- },
17
- "repository": {
18
- "type": "git",
19
- "url": "git+https://github.com/ZiProject/ZiPlayer.git"
20
- },
21
- "license": "MIT",
22
- "author": "Ziji",
23
- "main": "dist/index.js",
24
- "types": "dist/index.d.ts",
25
- "scripts": {
26
- "build": "tsc",
27
- "dev": "tsc --watch",
28
- "prepare": "npm run build"
29
- },
30
- "dependencies": {
31
- "@zibot/scdl": "^0.0.5",
32
- "@zibot/zitts": "^0.0.3",
33
- "axios": "^1.12.2",
34
- "cli-progress": "^3.12.0",
35
- "googlevideo": "^1.0.0",
36
- "music-metadata": "^11.9.0",
37
- "youtube-sr": "^4.3.4",
38
- "youtubei.js": "^16.0.1",
39
- "ziplayer": "^0.2.1"
40
- },
41
- "devDependencies": {
42
- "@types/node": "^20.0.0",
43
- "typescript": "^5.0.0"
44
- }
45
- }
1
+ {
2
+ "name": "@ziplayer/plugin",
3
+ "version": "0.2.1-dev-1",
4
+ "description": "A modular Discord voice player with plugin system",
5
+ "keywords": [
6
+ "ZiPlayer",
7
+ "@ziplayer/plugin",
8
+ "discord",
9
+ "music",
10
+ "player",
11
+ "voice"
12
+ ],
13
+ "homepage": "https://player.ziji.world",
14
+ "bugs": {
15
+ "url": "https://github.com/ZiProject/ZiPlayer/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/ZiProject/ZiPlayer.git"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Ziji",
23
+ "main": "dist/index.js",
24
+ "types": "dist/index.d.ts",
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "dev": "tsc --watch",
28
+ "prepare": "npm run build"
29
+ },
30
+ "dependencies": {
31
+ "@zibot/scdl": "^0.0.6",
32
+ "@zibot/zitts": "^0.0.3",
33
+ "axios": "^1.13.2",
34
+ "bgutils-js": "^3.2.0",
35
+ "googlevideo": "^4.0.4",
36
+ "jsdom": "^28.1.0",
37
+ "music-metadata": "^11.9.0",
38
+ "youtubei.js": "^16.0.1",
39
+ "ziplayer": "^0.2.3"
40
+ },
41
+ "devDependencies": {
42
+ "@types/jsdom": "^27.0.0",
43
+ "@types/node": "^20.0.0",
44
+ "typescript": "^5.0.0"
45
+ }
46
+ }