@ziplayer/plugin 0.1.2 → 0.1.40
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 +180 -180
- package/YTSR_README.md +310 -310
- package/dist/TTSPlugin.js +2 -0
- package/dist/TTSPlugin.js.map +1 -1
- package/dist/YTSRPlugin.d.ts.map +1 -1
- package/dist/YTSRPlugin.js +17 -1
- package/dist/YTSRPlugin.js.map +1 -1
- package/dist/YouTubePlugin.d.ts +15 -6
- package/dist/YouTubePlugin.d.ts.map +1 -1
- package/dist/YouTubePlugin.js +122 -47
- package/dist/YouTubePlugin.js.map +1 -1
- package/dist/utils/progress-bar.d.ts +8 -0
- package/dist/utils/progress-bar.d.ts.map +1 -0
- package/dist/utils/progress-bar.js +24 -0
- package/dist/utils/progress-bar.js.map +1 -0
- package/dist/utils/sabr-stream-factory.d.ts +25 -0
- package/dist/utils/sabr-stream-factory.d.ts.map +1 -0
- package/dist/utils/sabr-stream-factory.js +83 -0
- package/dist/utils/sabr-stream-factory.js.map +1 -0
- package/dist/utils/stream-converter.d.ts +10 -0
- package/dist/utils/stream-converter.d.ts.map +1 -0
- package/dist/utils/stream-converter.js +78 -0
- package/dist/utils/stream-converter.js.map +1 -0
- package/package.json +5 -3
- package/src/SpotifyPlugin.ts +312 -312
- package/src/TTSPlugin.ts +361 -361
- package/src/YTSRPlugin.ts +596 -583
- package/src/YouTubePlugin.ts +620 -528
- package/src/types/googlevideo.d.ts +45 -0
- package/src/utils/sabr-stream-factory.ts +96 -0
- package/src/utils/stream-converter.ts +87 -0
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface SabrPlaybackOptions {
|
|
2
|
+
preferWebM?: boolean;
|
|
3
|
+
preferOpus?: boolean;
|
|
4
|
+
videoQuality?: string;
|
|
5
|
+
audioQuality?: string;
|
|
6
|
+
enabledTrackTypes?: any;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface StreamResult {
|
|
10
|
+
videoStream: ReadableStream;
|
|
11
|
+
audioStream: ReadableStream;
|
|
12
|
+
selectedFormats: {
|
|
13
|
+
videoFormat: any;
|
|
14
|
+
audioFormat: any;
|
|
15
|
+
};
|
|
16
|
+
videoTitle: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module "googlevideo/sabr-stream" {
|
|
20
|
+
export interface SabrPlaybackOptions {
|
|
21
|
+
preferWebM?: boolean;
|
|
22
|
+
preferOpus?: boolean;
|
|
23
|
+
videoQuality?: string;
|
|
24
|
+
audioQuality?: string;
|
|
25
|
+
enabledTrackTypes?: any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StreamResult {
|
|
29
|
+
videoStream: ReadableStream;
|
|
30
|
+
audioStream: ReadableStream;
|
|
31
|
+
selectedFormats: {
|
|
32
|
+
videoFormat: any;
|
|
33
|
+
audioFormat: any;
|
|
34
|
+
};
|
|
35
|
+
videoTitle: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createSabrStream(videoId: string, options: SabrPlaybackOptions): Promise<{ streamResults: StreamResult }>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
declare module "googlevideo/utils" {
|
|
42
|
+
export enum EnabledTrackTypes {
|
|
43
|
+
VIDEO_AND_AUDIO = "VIDEO_AND_AUDIO",
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createWriteStream } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { tmpdir } from "os";
|
|
4
|
+
|
|
5
|
+
// Import type declarations
|
|
6
|
+
import type { SabrPlaybackOptions, StreamResult } from "../types/googlevideo";
|
|
7
|
+
|
|
8
|
+
// Re-export types for external use
|
|
9
|
+
export type { StreamResult, SabrPlaybackOptions };
|
|
10
|
+
|
|
11
|
+
export interface OutputStream {
|
|
12
|
+
stream: NodeJS.WritableStream;
|
|
13
|
+
filePath: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a sabr stream for YouTube video download
|
|
18
|
+
*/
|
|
19
|
+
export async function createSabrStream(videoId: string, options: SabrPlaybackOptions): Promise<{ streamResults: StreamResult }> {
|
|
20
|
+
try {
|
|
21
|
+
// Dynamic import to avoid build-time errors
|
|
22
|
+
const sabrModule = require("googlevideo/sabr-stream") as any;
|
|
23
|
+
const createSabrStreamImpl = sabrModule.createSabrStream;
|
|
24
|
+
|
|
25
|
+
const streamResults = await createSabrStreamImpl(videoId, options);
|
|
26
|
+
|
|
27
|
+
return { streamResults };
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// Fallback implementation if sabr download is not available
|
|
30
|
+
throw new Error(`Sabr download not available: ${error}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates an output stream for writing downloaded content
|
|
36
|
+
*/
|
|
37
|
+
export function createOutputStream(videoTitle: string, mimeType: string): OutputStream {
|
|
38
|
+
const sanitizedTitle = videoTitle.replace(/[<>:"/\\|?*]/g, "_").substring(0, 100);
|
|
39
|
+
const extension = getExtensionFromMimeType(mimeType);
|
|
40
|
+
const fileName = `${sanitizedTitle}.${extension}`;
|
|
41
|
+
const filePath = join(tmpdir(), fileName);
|
|
42
|
+
|
|
43
|
+
const stream = createWriteStream(filePath);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
stream,
|
|
47
|
+
filePath,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a stream sink for piping data with progress tracking
|
|
53
|
+
*/
|
|
54
|
+
export function createStreamSink(format: any, outputStream: NodeJS.WritableStream, progressBar: any) {
|
|
55
|
+
return new WritableStream({
|
|
56
|
+
start() {
|
|
57
|
+
// Initialize progress tracking
|
|
58
|
+
},
|
|
59
|
+
write(chunk) {
|
|
60
|
+
outputStream.write(chunk);
|
|
61
|
+
if (progressBar) {
|
|
62
|
+
progressBar.increment(chunk.length);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
close() {
|
|
66
|
+
outputStream.end();
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Gets file extension from MIME type
|
|
73
|
+
*/
|
|
74
|
+
function getExtensionFromMimeType(mimeType: string): string {
|
|
75
|
+
const mimeMap: { [key: string]: string } = {
|
|
76
|
+
"audio/mp4": "m4a",
|
|
77
|
+
"audio/webm": "webm",
|
|
78
|
+
"audio/ogg": "ogg",
|
|
79
|
+
"video/mp4": "mp4",
|
|
80
|
+
"video/webm": "webm",
|
|
81
|
+
"video/ogg": "ogv",
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return mimeMap[mimeType] || "bin";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Default sabr playback options
|
|
89
|
+
*/
|
|
90
|
+
export const DEFAULT_SABR_OPTIONS: SabrPlaybackOptions = {
|
|
91
|
+
preferWebM: true,
|
|
92
|
+
preferOpus: true,
|
|
93
|
+
videoQuality: "720p",
|
|
94
|
+
audioQuality: "AUDIO_QUALITY_MEDIUM",
|
|
95
|
+
enabledTrackTypes: "VIDEO_AND_AUDIO",
|
|
96
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts a Web ReadableStream to a Node.js Readable stream
|
|
5
|
+
*/
|
|
6
|
+
export function webStreamToNodeStream(webStream: ReadableStream): Readable {
|
|
7
|
+
console.log("🔄 webStreamToNodeStream: Starting conversion");
|
|
8
|
+
|
|
9
|
+
const nodeStream = new Readable({
|
|
10
|
+
read() {
|
|
11
|
+
// This will be handled by the Web Stream reader
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Create a reader from the Web Stream
|
|
16
|
+
const reader = webStream.getReader();
|
|
17
|
+
console.log("🔄 webStreamToNodeStream: Got reader");
|
|
18
|
+
|
|
19
|
+
// Read chunks and push to Node.js stream
|
|
20
|
+
const pump = async () => {
|
|
21
|
+
try {
|
|
22
|
+
console.log("🔄 webStreamToNodeStream: Starting pump");
|
|
23
|
+
while (true) {
|
|
24
|
+
const { done, value } = await reader.read();
|
|
25
|
+
if (done) {
|
|
26
|
+
console.log("🔄 webStreamToNodeStream: Stream ended");
|
|
27
|
+
nodeStream.push(null); // End the stream
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
console.log(`🔄 webStreamToNodeStream: Pushing chunk of ${value.length} bytes`);
|
|
31
|
+
nodeStream.push(Buffer.from(value));
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("🔄 webStreamToNodeStream: Error in pump:", error);
|
|
35
|
+
nodeStream.destroy(error as Error);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Start pumping data
|
|
40
|
+
pump();
|
|
41
|
+
|
|
42
|
+
console.log("🔄 webStreamToNodeStream: Conversion complete, returning Node.js stream");
|
|
43
|
+
return nodeStream;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Converts a Web ReadableStream to a Node.js Readable stream with progress tracking
|
|
48
|
+
*/
|
|
49
|
+
export function webStreamToNodeStreamWithProgress(
|
|
50
|
+
webStream: ReadableStream,
|
|
51
|
+
progressCallback?: (bytesRead: number) => void,
|
|
52
|
+
): Readable {
|
|
53
|
+
const nodeStream = new Readable({
|
|
54
|
+
read() {
|
|
55
|
+
// This will be handled by the Web Stream reader
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
let bytesRead = 0;
|
|
60
|
+
const reader = webStream.getReader();
|
|
61
|
+
|
|
62
|
+
const pump = async () => {
|
|
63
|
+
try {
|
|
64
|
+
while (true) {
|
|
65
|
+
const { done, value } = await reader.read();
|
|
66
|
+
if (done) {
|
|
67
|
+
nodeStream.push(null); // End the stream
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const buffer = Buffer.from(value);
|
|
72
|
+
nodeStream.push(buffer);
|
|
73
|
+
|
|
74
|
+
bytesRead += buffer.length;
|
|
75
|
+
if (progressCallback) {
|
|
76
|
+
progressCallback(bytesRead);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
nodeStream.destroy(error as Error);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
pump();
|
|
85
|
+
|
|
86
|
+
return nodeStream;
|
|
87
|
+
}
|