From 329e6ebef5643fedc4cd4717c9c0bb489ac6113b Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Thu, 11 Dec 2025 23:06:21 +0000 Subject: [PATCH] update --- dist_ts/00_commitinfo_data.d.ts | 8 - dist_ts/00_commitinfo_data.js | 9 - dist_ts/classes.ffmpegcommand.d.ts | 288 ------------ dist_ts/classes.ffmpegcommand.js | 731 ----------------------------- dist_ts/classes.smartffmpeg.d.ts | 185 -------- dist_ts/classes.smartffmpeg.js | 586 ----------------------- dist_ts/index.d.ts | 3 - dist_ts/index.js | 7 - dist_ts/interfaces.d.ts | 138 ------ dist_ts/interfaces.js | 2 - dist_ts/plugins.d.ts | 9 - dist_ts/plugins.js | 15 - 12 files changed, 1981 deletions(-) delete mode 100644 dist_ts/00_commitinfo_data.d.ts delete mode 100644 dist_ts/00_commitinfo_data.js delete mode 100644 dist_ts/classes.ffmpegcommand.d.ts delete mode 100644 dist_ts/classes.ffmpegcommand.js delete mode 100644 dist_ts/classes.smartffmpeg.d.ts delete mode 100644 dist_ts/classes.smartffmpeg.js delete mode 100644 dist_ts/index.d.ts delete mode 100644 dist_ts/index.js delete mode 100644 dist_ts/interfaces.d.ts delete mode 100644 dist_ts/interfaces.js delete mode 100644 dist_ts/plugins.d.ts delete mode 100644 dist_ts/plugins.js diff --git a/dist_ts/00_commitinfo_data.d.ts b/dist_ts/00_commitinfo_data.d.ts deleted file mode 100644 index 931e8fc..0000000 --- a/dist_ts/00_commitinfo_data.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * autocreated commitinfo by @push.rocks/commitinfo - */ -export declare const commitinfo: { - name: string; - version: string; - description: string; -}; diff --git a/dist_ts/00_commitinfo_data.js b/dist_ts/00_commitinfo_data.js deleted file mode 100644 index 5bca4da..0000000 --- a/dist_ts/00_commitinfo_data.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * autocreated commitinfo by @push.rocks/commitinfo - */ -export const commitinfo = { - name: '@push.rocks/smartffmpeg', - version: '1.0.0', - description: 'A fast Node.js module for media file conversion using ffmpeg' -}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx5QkFBeUI7SUFDL0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDhEQUE4RDtDQUM1RSxDQUFBIn0= \ No newline at end of file diff --git a/dist_ts/classes.ffmpegcommand.d.ts b/dist_ts/classes.ffmpegcommand.d.ts deleted file mode 100644 index 022dbe5..0000000 --- a/dist_ts/classes.ffmpegcommand.d.ts +++ /dev/null @@ -1,288 +0,0 @@ -import type * as interfaces from './interfaces.js'; -/** - * Input source for FfmpegCommand - * Supports file paths, memory buffers, and Web Streams - */ -export type TFfmpegInput = string | Buffer | Uint8Array | ReadableStream; -/** - * Output destination for FfmpegCommand - */ -export type TFfmpegOutput = string | 'buffer' | 'stream' | WritableStream; -/** - * Input options when using Buffer or Stream - */ -export interface IInputOptions { - /** Input format (required for buffer/stream input) */ - format?: interfaces.TOutputFormat; - /** Input duration hint for progress calculation */ - duration?: number; -} -/** - * Result of running an FfmpegCommand - */ -export interface IFfmpegResult { - /** Output buffer (when outputting to buffer) */ - buffer?: Buffer; - /** Output stream (when outputting to stream) */ - stream?: ReadableStream; - /** Path to output file (when outputting to file) */ - outputPath?: string; - /** Duration of processing in ms */ - processingTime: number; -} -/** - * Progress callback type for FfmpegCommand - */ -export type TFfmpegProgressCallback = (progress: interfaces.IProgressInfo) => void; -/** - * Modern fluent builder API for ffmpeg commands - * - * @example - * ```typescript - * // File to file - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .audioBitrate('128k') - * .output('/path/to/output.mp4') - * .run(); - * - * // Buffer to buffer - * const outputBuffer = await ffmpeg.create() - * .input(inputBuffer, { format: 'mp4' }) - * .videoCodec('libx264') - * .toBuffer('webm'); - * - * // With progress - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .onProgress(p => console.log(`${p.percent}%`)) - * .output('/path/to/output.mp4') - * .run(); - * ``` - */ -export declare class FfmpegCommand { - private ffmpegPath; - private ffprobePath; - private inputSource; - private inputOpts; - private customInputArgs; - private outputDest; - private outputFormat; - private customOutputArgs; - private _videoCodec; - private _videoBitrate; - private _width; - private _height; - private _fps; - private _crf; - private _preset; - private _noVideo; - private _audioCodec; - private _audioBitrate; - private _sampleRate; - private _audioChannels; - private _noAudio; - private _startTime; - private _duration; - private videoFilters; - private audioFilters; - private _complexFilter; - private extraInputArgs; - private extraOutputArgs; - private progressCallback; - private _overwrite; - constructor(ffmpegPath: string, ffprobePath: string); - /** - * Set the input source - * @param source - File path, Buffer, or Readable stream - * @param options - Input options (format required for buffer/stream) - */ - input(source: TFfmpegInput, options?: IInputOptions): this; - /** - * Seek to position before input (fast seek) - * @param time - Time in seconds or timecode string - */ - seekInput(time: number | string): this; - /** - * Add custom input arguments - */ - inputArgs(...args: string[]): this; - /** - * Set video codec - */ - videoCodec(codec: interfaces.TVideoCodec): this; - /** - * Set video bitrate - * @param bitrate - e.g., '1M', '2000k' - */ - videoBitrate(bitrate: string): this; - /** - * Set output dimensions - * @param width - Width in pixels (-1 for auto) - * @param height - Height in pixels (-1 for auto) - */ - size(width: number, height?: number): this; - /** - * Set frame rate - */ - fps(rate: number): this; - /** - * Set Constant Rate Factor (quality) - * @param value - 0-51, lower is better quality - */ - crf(value: number): this; - /** - * Set encoding preset - */ - preset(value: interfaces.TPreset): this; - /** - * Remove video stream - */ - noVideo(): this; - /** - * Add a video filter - * @param filter - Filter string (e.g., 'scale=1920:1080', 'hflip') - */ - videoFilter(filter: string): this; - /** - * Scale video - * @param width - Width (-1 or -2 for auto) - * @param height - Height (-1 or -2 for auto) - */ - scale(width: number | string, height: number | string): this; - /** - * Crop video - */ - crop(width: number, height: number, x?: number, y?: number): this; - /** - * Rotate video - * @param angle - Rotation in radians or 'PI/2', 'PI', etc. - */ - rotate(angle: number | string): this; - /** - * Flip video horizontally - */ - flipHorizontal(): this; - /** - * Flip video vertically - */ - flipVertical(): this; - /** - * Add padding to video - */ - pad(width: number, height: number, x?: number, y?: number, color?: string): this; - /** - * Set audio codec - */ - audioCodec(codec: interfaces.TAudioCodec): this; - /** - * Set audio bitrate - * @param bitrate - e.g., '128k', '320k' - */ - audioBitrate(bitrate: string): this; - /** - * Set audio sample rate - * @param rate - Sample rate in Hz (e.g., 44100, 48000) - */ - sampleRate(rate: number): this; - /** - * Set number of audio channels - * @param channels - 1 for mono, 2 for stereo - */ - audioChannels(channels: number): this; - /** - * Remove audio stream - */ - noAudio(): this; - /** - * Add an audio filter - * @param filter - Filter string (e.g., 'volume=2', 'aecho=0.8:0.88:60:0.4') - */ - audioFilter(filter: string): this; - /** - * Set audio volume - * @param level - Volume multiplier (e.g., 2 for double, 0.5 for half) - */ - volume(level: number): this; - /** - * Normalize audio - */ - normalize(): this; - /** - * Set start time (seek) - * @param time - Time in seconds or timecode string - */ - seek(time: number | string): this; - /** - * Set output duration - * @param time - Duration in seconds or timecode string - */ - duration(time: number | string): this; - /** - * Set both start and end time - */ - trim(start: number | string, end: number | string): this; - /** - * Set a complex filter graph - * @param filterGraph - Complex filter string - */ - complexFilter(filterGraph: string): this; - /** - * Set output format - */ - format(fmt: interfaces.TOutputFormat): this; - /** - * Set output destination (file path) - */ - output(dest: string): this; - /** - * Add custom output arguments - */ - outputArgs(...args: string[]): this; - /** - * Set overwrite flag - */ - overwrite(value?: boolean): this; - /** - * Set progress callback - */ - onProgress(callback: TFfmpegProgressCallback): this; - /** - * Run the command and output to file - */ - run(): Promise; - /** - * Run the command and return output as Buffer - * @param format - Output format - */ - toBuffer(format?: interfaces.TOutputFormat): Promise; - /** - * Run the command and return output as Web ReadableStream - * @param format - Output format - */ - toStream(format?: interfaces.TOutputFormat): ReadableStream; - /** - * Pipe output to a Web WritableStream - * @param writable - Web WritableStream - * @param format - Output format - */ - pipe(writable: WritableStream, format?: interfaces.TOutputFormat): Promise; - /** - * Get the ffmpeg arguments that would be used (for debugging) - */ - getArgs(outputPath?: string): string[]; - private buildArgs; - private execute; - private executeToBuffer; - private executeToNodeStream; - private parseProgress; - private getInputDuration; - private runProbe; - private formatTime; - private isNodeStream; - private isWebReadableStream; - private isMemoryInput; - private pipeInputToProcess; -} diff --git a/dist_ts/classes.ffmpegcommand.js b/dist_ts/classes.ffmpegcommand.js deleted file mode 100644 index 304b554..0000000 --- a/dist_ts/classes.ffmpegcommand.js +++ /dev/null @@ -1,731 +0,0 @@ -import * as plugins from './plugins.js'; -import { Readable, Writable } from 'stream'; -/** - * Modern fluent builder API for ffmpeg commands - * - * @example - * ```typescript - * // File to file - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .audioBitrate('128k') - * .output('/path/to/output.mp4') - * .run(); - * - * // Buffer to buffer - * const outputBuffer = await ffmpeg.create() - * .input(inputBuffer, { format: 'mp4' }) - * .videoCodec('libx264') - * .toBuffer('webm'); - * - * // With progress - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .onProgress(p => console.log(`${p.percent}%`)) - * .output('/path/to/output.mp4') - * .run(); - * ``` - */ -export class FfmpegCommand { - ffmpegPath; - ffprobePath; - // Input configuration - inputSource = null; - inputOpts = {}; - customInputArgs = []; - // Output configuration - outputDest = null; - outputFormat = null; - customOutputArgs = []; - // Video settings - _videoCodec = null; - _videoBitrate = null; - _width = null; - _height = null; - _fps = null; - _crf = null; - _preset = null; - _noVideo = false; - // Audio settings - _audioCodec = null; - _audioBitrate = null; - _sampleRate = null; - _audioChannels = null; - _noAudio = false; - // Timing - _startTime = null; - _duration = null; - // Video filters - videoFilters = []; - // Audio filters - audioFilters = []; - // Complex filter - _complexFilter = null; - // Extra arguments - extraInputArgs = []; - extraOutputArgs = []; - // Callbacks - progressCallback = null; - // Options - _overwrite = true; - constructor(ffmpegPath, ffprobePath) { - this.ffmpegPath = ffmpegPath; - this.ffprobePath = ffprobePath; - } - // ==================== INPUT METHODS ==================== - /** - * Set the input source - * @param source - File path, Buffer, or Readable stream - * @param options - Input options (format required for buffer/stream) - */ - input(source, options = {}) { - this.inputSource = source; - this.inputOpts = options; - return this; - } - /** - * Seek to position before input (fast seek) - * @param time - Time in seconds or timecode string - */ - seekInput(time) { - this._startTime = time; - return this; - } - /** - * Add custom input arguments - */ - inputArgs(...args) { - this.extraInputArgs.push(...args); - return this; - } - // ==================== VIDEO METHODS ==================== - /** - * Set video codec - */ - videoCodec(codec) { - this._videoCodec = codec; - return this; - } - /** - * Set video bitrate - * @param bitrate - e.g., '1M', '2000k' - */ - videoBitrate(bitrate) { - this._videoBitrate = bitrate; - return this; - } - /** - * Set output dimensions - * @param width - Width in pixels (-1 for auto) - * @param height - Height in pixels (-1 for auto) - */ - size(width, height) { - this._width = width; - this._height = height ?? null; - return this; - } - /** - * Set frame rate - */ - fps(rate) { - this._fps = rate; - return this; - } - /** - * Set Constant Rate Factor (quality) - * @param value - 0-51, lower is better quality - */ - crf(value) { - this._crf = value; - return this; - } - /** - * Set encoding preset - */ - preset(value) { - this._preset = value; - return this; - } - /** - * Remove video stream - */ - noVideo() { - this._noVideo = true; - return this; - } - /** - * Add a video filter - * @param filter - Filter string (e.g., 'scale=1920:1080', 'hflip') - */ - videoFilter(filter) { - this.videoFilters.push(filter); - return this; - } - /** - * Scale video - * @param width - Width (-1 or -2 for auto) - * @param height - Height (-1 or -2 for auto) - */ - scale(width, height) { - // Use -2 to ensure even dimensions - const w = width === -1 ? '-2' : String(width); - const h = height === -1 ? '-2' : String(height); - this.videoFilters.push(`scale=${w}:${h}`); - return this; - } - /** - * Crop video - */ - crop(width, height, x = 0, y = 0) { - this.videoFilters.push(`crop=${width}:${height}:${x}:${y}`); - return this; - } - /** - * Rotate video - * @param angle - Rotation in radians or 'PI/2', 'PI', etc. - */ - rotate(angle) { - this.videoFilters.push(`rotate=${angle}`); - return this; - } - /** - * Flip video horizontally - */ - flipHorizontal() { - this.videoFilters.push('hflip'); - return this; - } - /** - * Flip video vertically - */ - flipVertical() { - this.videoFilters.push('vflip'); - return this; - } - /** - * Add padding to video - */ - pad(width, height, x = 0, y = 0, color = 'black') { - this.videoFilters.push(`pad=${width}:${height}:${x}:${y}:${color}`); - return this; - } - // ==================== AUDIO METHODS ==================== - /** - * Set audio codec - */ - audioCodec(codec) { - this._audioCodec = codec; - return this; - } - /** - * Set audio bitrate - * @param bitrate - e.g., '128k', '320k' - */ - audioBitrate(bitrate) { - this._audioBitrate = bitrate; - return this; - } - /** - * Set audio sample rate - * @param rate - Sample rate in Hz (e.g., 44100, 48000) - */ - sampleRate(rate) { - this._sampleRate = rate; - return this; - } - /** - * Set number of audio channels - * @param channels - 1 for mono, 2 for stereo - */ - audioChannels(channels) { - this._audioChannels = channels; - return this; - } - /** - * Remove audio stream - */ - noAudio() { - this._noAudio = true; - return this; - } - /** - * Add an audio filter - * @param filter - Filter string (e.g., 'volume=2', 'aecho=0.8:0.88:60:0.4') - */ - audioFilter(filter) { - this.audioFilters.push(filter); - return this; - } - /** - * Set audio volume - * @param level - Volume multiplier (e.g., 2 for double, 0.5 for half) - */ - volume(level) { - this.audioFilters.push(`volume=${level}`); - return this; - } - /** - * Normalize audio - */ - normalize() { - this.audioFilters.push('loudnorm'); - return this; - } - // ==================== TIMING METHODS ==================== - /** - * Set start time (seek) - * @param time - Time in seconds or timecode string - */ - seek(time) { - this._startTime = time; - return this; - } - /** - * Set output duration - * @param time - Duration in seconds or timecode string - */ - duration(time) { - this._duration = time; - return this; - } - /** - * Set both start and end time - */ - trim(start, end) { - this._startTime = start; - // Calculate duration from end - start - if (typeof start === 'number' && typeof end === 'number') { - this._duration = end - start; - } - else { - // For string timestamps, set end time as duration (approximate) - this._duration = end; - } - return this; - } - // ==================== FILTER METHODS ==================== - /** - * Set a complex filter graph - * @param filterGraph - Complex filter string - */ - complexFilter(filterGraph) { - this._complexFilter = filterGraph; - return this; - } - // ==================== OUTPUT METHODS ==================== - /** - * Set output format - */ - format(fmt) { - this.outputFormat = fmt; - return this; - } - /** - * Set output destination (file path) - */ - output(dest) { - this.outputDest = dest; - return this; - } - /** - * Add custom output arguments - */ - outputArgs(...args) { - this.extraOutputArgs.push(...args); - return this; - } - /** - * Set overwrite flag - */ - overwrite(value = true) { - this._overwrite = value; - return this; - } - // ==================== CALLBACK METHODS ==================== - /** - * Set progress callback - */ - onProgress(callback) { - this.progressCallback = callback; - return this; - } - // ==================== EXECUTION METHODS ==================== - /** - * Run the command and output to file - */ - async run() { - if (!this.outputDest || typeof this.outputDest !== 'string') { - throw new Error('Output path must be set. Use .output() or .toBuffer()/.toStream()'); - } - const startTime = Date.now(); - const args = this.buildArgs(this.outputDest); - await this.execute(args); - return { - outputPath: this.outputDest, - processingTime: Date.now() - startTime, - }; - } - /** - * Run the command and return output as Buffer - * @param format - Output format - */ - async toBuffer(format) { - if (format) { - this.outputFormat = format; - } - if (!this.outputFormat) { - throw new Error('Output format must be specified when outputting to buffer. Use .format() or pass format to .toBuffer()'); - } - const args = this.buildArgs('pipe:1'); - return this.executeToBuffer(args); - } - /** - * Run the command and return output as Web ReadableStream - * @param format - Output format - */ - toStream(format) { - if (format) { - this.outputFormat = format; - } - if (!this.outputFormat) { - throw new Error('Output format must be specified when outputting to stream. Use .format() or pass format to .toStream()'); - } - const args = this.buildArgs('pipe:1'); - const nodeStream = this.executeToNodeStream(args); - // Convert Node.js Readable to Web ReadableStream - return Readable.toWeb(nodeStream); - } - /** - * Pipe output to a Web WritableStream - * @param writable - Web WritableStream - * @param format - Output format - */ - async pipe(writable, format) { - if (format) { - this.outputFormat = format; - } - if (!this.outputFormat) { - throw new Error('Output format must be specified when piping. Use .format() or pass format to .pipe()'); - } - const args = this.buildArgs('pipe:1'); - const nodeReadable = this.executeToNodeStream(args); - // Convert Node.js Readable to Web ReadableStream and pipe to WritableStream - const webReadable = Readable.toWeb(nodeReadable); - await webReadable.pipeTo(writable); - } - /** - * Get the ffmpeg arguments that would be used (for debugging) - */ - getArgs(outputPath = 'output') { - return this.buildArgs(outputPath); - } - // ==================== PRIVATE METHODS ==================== - buildArgs(outputPath) { - const args = []; - // Overwrite flag - if (this._overwrite) { - args.push('-y'); - } - // Seek before input (fast seek) - if (this._startTime !== null) { - args.push('-ss', this.formatTime(this._startTime)); - } - // Extra input args - args.push(...this.extraInputArgs); - // Input format (for buffer/stream input) - if (this.inputOpts.format && this.isMemoryInput()) { - args.push('-f', this.inputOpts.format); - } - // Input source - if (typeof this.inputSource === 'string') { - args.push('-i', this.inputSource); - } - else { - // Buffer or stream - read from stdin - args.push('-i', 'pipe:0'); - } - // Duration (after input) - if (this._duration !== null) { - args.push('-t', this.formatTime(this._duration)); - } - // Video options - if (this._noVideo) { - args.push('-vn'); - } - else { - if (this._videoCodec) { - args.push('-c:v', this._videoCodec); - } - if (this._videoBitrate) { - args.push('-b:v', this._videoBitrate); - } - if (this._crf !== null) { - args.push('-crf', String(this._crf)); - } - if (this._preset) { - args.push('-preset', this._preset); - } - if (this._fps) { - args.push('-r', String(this._fps)); - } - // Size (via scale filter or direct) - if (this._width !== null || this._height !== null) { - const w = this._width !== null ? String(this._width) : '-2'; - const h = this._height !== null ? String(this._height) : '-2'; - this.videoFilters.unshift(`scale=${w}:${h}`); - } - } - // Audio options - if (this._noAudio) { - args.push('-an'); - } - else { - if (this._audioCodec) { - args.push('-c:a', this._audioCodec); - } - if (this._audioBitrate) { - args.push('-b:a', this._audioBitrate); - } - if (this._sampleRate) { - args.push('-ar', String(this._sampleRate)); - } - if (this._audioChannels) { - args.push('-ac', String(this._audioChannels)); - } - } - // Complex filter - if (this._complexFilter) { - args.push('-filter_complex', this._complexFilter); - } - else { - // Video filters - if (this.videoFilters.length > 0) { - args.push('-vf', this.videoFilters.join(',')); - } - // Audio filters - if (this.audioFilters.length > 0) { - args.push('-af', this.audioFilters.join(',')); - } - } - // Output format - if (this.outputFormat) { - args.push('-f', this.outputFormat); - } - // Extra output args - args.push(...this.extraOutputArgs); - // Output - args.push(outputPath); - return args; - } - async execute(args) { - const inputDuration = await this.getInputDuration(); - // Add progress output if callback is set - if (this.progressCallback) { - args.unshift('-progress', 'pipe:2'); - } - return new Promise((resolve, reject) => { - const proc = plugins.child_process.spawn(this.ffmpegPath, args, { - stdio: ['pipe', 'pipe', 'pipe'], - }); - // Handle input - this.pipeInputToProcess(proc); - // Handle progress - if (this.progressCallback && proc.stderr) { - this.parseProgress(proc.stderr, inputDuration); - } - let stderr = ''; - proc.stderr?.on('data', (data) => { - stderr += data.toString(); - }); - proc.on('close', (code) => { - if (code === 0) { - resolve(); - } - else { - reject(new Error(`FFmpeg exited with code ${code}: ${stderr}`)); - } - }); - proc.on('error', reject); - }); - } - executeToBuffer(args) { - const inputDuration = this.inputOpts.duration; - return new Promise((resolve, reject) => { - const proc = plugins.child_process.spawn(this.ffmpegPath, args, { - stdio: ['pipe', 'pipe', 'pipe'], - }); - // Handle input - this.pipeInputToProcess(proc); - const chunks = []; - proc.stdout?.on('data', (chunk) => { - chunks.push(chunk); - }); - // Handle progress on stderr - if (this.progressCallback && proc.stderr) { - this.parseProgress(proc.stderr, inputDuration); - } - let stderr = ''; - proc.stderr?.on('data', (data) => { - stderr += data.toString(); - }); - proc.on('close', (code) => { - if (code === 0) { - resolve(Buffer.concat(chunks)); - } - else { - reject(new Error(`FFmpeg exited with code ${code}: ${stderr}`)); - } - }); - proc.on('error', reject); - }); - } - executeToNodeStream(args) { - const proc = plugins.child_process.spawn(this.ffmpegPath, args, { - stdio: ['pipe', 'pipe', 'pipe'], - }); - // Handle input - this.pipeInputToProcess(proc); - // Handle progress on stderr - if (this.progressCallback && proc.stderr) { - this.parseProgress(proc.stderr, this.inputOpts.duration); - } - proc.on('error', (err) => { - proc.stdout?.destroy(err); - }); - return proc.stdout; - } - parseProgress(stderr, duration) { - let progressData = {}; - stderr.on('data', (data) => { - const lines = data.toString().split('\n'); - for (const line of lines) { - const [key, value] = line.split('='); - if (!key || !value) - continue; - switch (key.trim()) { - case 'frame': - progressData.frame = parseInt(value, 10); - break; - case 'fps': - progressData.fps = parseFloat(value); - break; - case 'total_size': - progressData.size = parseInt(value, 10); - break; - case 'out_time_ms': - progressData.time = parseInt(value, 10) / 1000000; - if (duration && progressData.time) { - progressData.percent = Math.min(100, (progressData.time / duration) * 100); - } - break; - case 'bitrate': - progressData.bitrate = value.trim(); - break; - case 'speed': - progressData.speed = value.trim(); - break; - case 'progress': - if ((value.trim() === 'continue' || value.trim() === 'end') && - this.progressCallback && - progressData.frame !== undefined) { - this.progressCallback(progressData); - } - break; - } - } - }); - } - async getInputDuration() { - if (this.inputOpts.duration) { - return this.inputOpts.duration; - } - if (typeof this.inputSource !== 'string') { - return undefined; - } - try { - const result = await this.runProbe([ - '-v', 'quiet', - '-print_format', 'json', - '-show_format', - this.inputSource, - ]); - const data = JSON.parse(result); - return parseFloat(data.format?.duration) || undefined; - } - catch { - return undefined; - } - } - runProbe(args) { - return new Promise((resolve, reject) => { - const proc = plugins.child_process.spawn(this.ffprobePath, args); - let stdout = ''; - let stderr = ''; - proc.stdout?.on('data', (data) => { - stdout += data.toString(); - }); - proc.stderr?.on('data', (data) => { - stderr += data.toString(); - }); - proc.on('close', (code) => { - if (code === 0) { - resolve(stdout); - } - else { - reject(new Error(`FFprobe exited with code ${code}: ${stderr}`)); - } - }); - proc.on('error', reject); - }); - } - formatTime(time) { - if (typeof time === 'string') { - return time; - } - const hours = Math.floor(time / 3600); - const minutes = Math.floor((time % 3600) / 60); - const seconds = time % 60; - return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toFixed(3).padStart(6, '0')}`; - } - isNodeStream(value) { - return value !== null && - typeof value === 'object' && - typeof value.pipe === 'function' && - !(value instanceof ReadableStream); - } - isWebReadableStream(value) { - return value instanceof ReadableStream; - } - isMemoryInput() { - return Buffer.isBuffer(this.inputSource) || - this.inputSource instanceof Uint8Array || - this.isNodeStream(this.inputSource) || - this.isWebReadableStream(this.inputSource); - } - pipeInputToProcess(proc) { - if (Buffer.isBuffer(this.inputSource)) { - proc.stdin?.write(this.inputSource); - proc.stdin?.end(); - } - else if (this.inputSource instanceof Uint8Array) { - // Convert Uint8Array to Buffer - proc.stdin?.write(Buffer.from(this.inputSource)); - proc.stdin?.end(); - } - else if (this.isWebReadableStream(this.inputSource)) { - // Convert Web ReadableStream to Node.js Readable and pipe - // Cast to any to handle type mismatch between global ReadableStream and node:stream/web types - const nodeReadable = Readable.fromWeb(this.inputSource); - nodeReadable.pipe(proc.stdin); - } - else if (this.isNodeStream(this.inputSource)) { - this.inputSource.pipe(proc.stdin); - } - else if (typeof this.inputSource === 'string') { - proc.stdin?.end(); - } - } -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5mZm1wZWdjb21tYW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5mZm1wZWdjb21tYW5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBRXhDLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBa0Q1Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkJHO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFDaEIsVUFBVSxDQUFTO0lBQ25CLFdBQVcsQ0FBUztJQUU1QixzQkFBc0I7SUFDZCxXQUFXLEdBQXdCLElBQUksQ0FBQztJQUN4QyxTQUFTLEdBQWtCLEVBQUUsQ0FBQztJQUM5QixlQUFlLEdBQWEsRUFBRSxDQUFDO0lBRXZDLHVCQUF1QjtJQUNmLFVBQVUsR0FBeUIsSUFBSSxDQUFDO0lBQ3hDLFlBQVksR0FBb0MsSUFBSSxDQUFDO0lBQ3JELGdCQUFnQixHQUFhLEVBQUUsQ0FBQztJQUV4QyxpQkFBaUI7SUFDVCxXQUFXLEdBQWtDLElBQUksQ0FBQztJQUNsRCxhQUFhLEdBQWtCLElBQUksQ0FBQztJQUNwQyxNQUFNLEdBQWtCLElBQUksQ0FBQztJQUM3QixPQUFPLEdBQWtCLElBQUksQ0FBQztJQUM5QixJQUFJLEdBQWtCLElBQUksQ0FBQztJQUMzQixJQUFJLEdBQWtCLElBQUksQ0FBQztJQUMzQixPQUFPLEdBQThCLElBQUksQ0FBQztJQUMxQyxRQUFRLEdBQUcsS0FBSyxDQUFDO0lBRXpCLGlCQUFpQjtJQUNULFdBQVcsR0FBa0MsSUFBSSxDQUFDO0lBQ2xELGFBQWEsR0FBa0IsSUFBSSxDQUFDO0lBQ3BDLFdBQVcsR0FBa0IsSUFBSSxDQUFDO0lBQ2xDLGNBQWMsR0FBa0IsSUFBSSxDQUFDO0lBQ3JDLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFFekIsU0FBUztJQUNELFVBQVUsR0FBMkIsSUFBSSxD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 \ No newline at end of file diff --git a/dist_ts/classes.smartffmpeg.d.ts b/dist_ts/classes.smartffmpeg.d.ts deleted file mode 100644 index ac532b3..0000000 --- a/dist_ts/classes.smartffmpeg.d.ts +++ /dev/null @@ -1,185 +0,0 @@ -import type * as interfaces from './interfaces.js'; -import { FfmpegCommand, type TFfmpegInput, type IInputOptions } from './classes.ffmpegcommand.js'; -/** - * Event callback types - */ -export type TProgressCallback = (progress: interfaces.IProgressInfo) => void; -export type TErrorCallback = (error: Error) => void; -export type TEndCallback = () => void; -/** - * SmartFfmpeg - A fast Node.js module for media file conversion using ffmpeg - * - * @example Modern Builder API - * ```typescript - * const ffmpeg = new SmartFfmpeg(); - * - * // File to file with fluent API - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .audioBitrate('128k') - * .size(1920, 1080) - * .output('/path/to/output.mp4') - * .run(); - * - * // Buffer to buffer - * const outputBuffer = await ffmpeg.create() - * .input(inputBuffer, { format: 'mp4' }) - * .videoCodec('libx264') - * .toBuffer('webm'); - * - * // With progress tracking - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .onProgress(p => console.log(`${p.percent?.toFixed(1)}%`)) - * .output('/path/to/output.mp4') - * .run(); - * - * // Stream output - * const stream = ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .toStream('mp4'); - * ``` - * - * @example Legacy API (still supported) - * ```typescript - * await ffmpeg.convert('input.mp4', 'output.webm', { - * videoCodec: 'libvpx-vp9', - * audioBitrate: '128k' - * }); - * ``` - */ -export declare class SmartFfmpeg { - private ffmpegPath; - private ffprobePath; - constructor(); - /** - * Create a new FfmpegCommand builder for fluent API usage - * - * @example - * ```typescript - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .crf(23) - * .output('/path/to/output.mp4') - * .run(); - * ``` - */ - create(): FfmpegCommand; - /** - * Shorthand to create a command with input already set - * - * @example - * ```typescript - * // File input - * await ffmpeg.input('/path/to/input.mp4') - * .videoCodec('libx264') - * .output('/path/to/output.mp4') - * .run(); - * - * // Buffer input - * const output = await ffmpeg.input(buffer, { format: 'mp4' }) - * .videoCodec('libx264') - * .toBuffer('webm'); - * ``` - */ - input(source: TFfmpegInput, options?: IInputOptions): FfmpegCommand; - /** - * Get media file information using ffprobe - */ - getMediaInfo(inputPath: string): Promise; - /** - * Convert media file with specified options - */ - convert(inputPath: string, outputPath: string, options?: interfaces.IConversionOptions): Promise; - /** - * Convert media file with progress reporting - */ - convertWithProgress(inputPath: string, outputPath: string, options?: interfaces.IConversionOptions, onProgress?: TProgressCallback): Promise; - /** - * Extract audio from video file - */ - extractAudio(inputPath: string, outputPath: string, options?: Pick): Promise; - /** - * Remove audio from video file - */ - removeAudio(inputPath: string, outputPath: string, options?: Pick): Promise; - /** - * Take a screenshot at a specific time - */ - screenshot(inputPath: string, outputPath: string, options: interfaces.IScreenshotOptions): Promise; - /** - * Generate multiple thumbnails from video - */ - generateThumbnails(inputPath: string, outputDir: string, options: interfaces.IThumbnailOptions): Promise; - /** - * Resize video - */ - resize(inputPath: string, outputPath: string, width?: number, height?: number, options?: Omit): Promise; - /** - * Change video frame rate - */ - changeFrameRate(inputPath: string, outputPath: string, fps: number, options?: Omit): Promise; - /** - * Trim media file - */ - trim(inputPath: string, outputPath: string, startTime: number | string, duration: number | string, options?: Omit): Promise; - /** - * Convert to GIF - */ - toGif(inputPath: string, outputPath: string, options?: { - width?: number; - height?: number; - fps?: number; - startTime?: number | string; - duration?: number | string; - }): Promise; - /** - * Concatenate multiple media files - */ - concat(inputPaths: string[], outputPath: string, options?: interfaces.IConversionOptions): Promise; - /** - * Add audio to video - */ - addAudio(videoPath: string, audioPath: string, outputPath: string, options?: { - videoCodec?: interfaces.TVideoCodec; - audioCodec?: interfaces.TAudioCodec; - audioBitrate?: string; - shortest?: boolean; - overwrite?: boolean; - }): Promise; - /** - * Get available encoders - */ - getEncoders(): Promise; - /** - * Get available decoders - */ - getDecoders(): Promise; - /** - * Get available formats - */ - getFormats(): Promise; - /** - * Run ffmpeg with raw arguments - */ - runRaw(args: string[]): Promise<{ - stdout: string; - stderr: string; - }>; - /** - * Run ffprobe with raw arguments - */ - runProbeRaw(args: string[]): Promise<{ - stdout: string; - stderr: string; - }>; - private buildConversionArgs; - private buildScaleFilter; - private formatTime; - private parseStreamInfo; - private runProcess; -} diff --git a/dist_ts/classes.smartffmpeg.js b/dist_ts/classes.smartffmpeg.js deleted file mode 100644 index 755b627..0000000 --- a/dist_ts/classes.smartffmpeg.js +++ /dev/null @@ -1,586 +0,0 @@ -import * as plugins from './plugins.js'; -import { FfmpegCommand } from './classes.ffmpegcommand.js'; -/** - * SmartFfmpeg - A fast Node.js module for media file conversion using ffmpeg - * - * @example Modern Builder API - * ```typescript - * const ffmpeg = new SmartFfmpeg(); - * - * // File to file with fluent API - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .audioBitrate('128k') - * .size(1920, 1080) - * .output('/path/to/output.mp4') - * .run(); - * - * // Buffer to buffer - * const outputBuffer = await ffmpeg.create() - * .input(inputBuffer, { format: 'mp4' }) - * .videoCodec('libx264') - * .toBuffer('webm'); - * - * // With progress tracking - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .onProgress(p => console.log(`${p.percent?.toFixed(1)}%`)) - * .output('/path/to/output.mp4') - * .run(); - * - * // Stream output - * const stream = ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .toStream('mp4'); - * ``` - * - * @example Legacy API (still supported) - * ```typescript - * await ffmpeg.convert('input.mp4', 'output.webm', { - * videoCodec: 'libvpx-vp9', - * audioBitrate: '128k' - * }); - * ``` - */ -export class SmartFfmpeg { - ffmpegPath; - ffprobePath; - constructor() { - this.ffmpegPath = plugins.ffmpegBinaryPath; - this.ffprobePath = plugins.ffprobeBinaryPath; - } - // ==================== BUILDER API ==================== - /** - * Create a new FfmpegCommand builder for fluent API usage - * - * @example - * ```typescript - * await ffmpeg.create() - * .input('/path/to/input.mp4') - * .videoCodec('libx264') - * .crf(23) - * .output('/path/to/output.mp4') - * .run(); - * ``` - */ - create() { - return new FfmpegCommand(this.ffmpegPath, this.ffprobePath); - } - /** - * Shorthand to create a command with input already set - * - * @example - * ```typescript - * // File input - * await ffmpeg.input('/path/to/input.mp4') - * .videoCodec('libx264') - * .output('/path/to/output.mp4') - * .run(); - * - * // Buffer input - * const output = await ffmpeg.input(buffer, { format: 'mp4' }) - * .videoCodec('libx264') - * .toBuffer('webm'); - * ``` - */ - input(source, options) { - return this.create().input(source, options); - } - // ==================== LEGACY API ==================== - /** - * Get media file information using ffprobe - */ - async getMediaInfo(inputPath) { - const args = [ - '-v', 'quiet', - '-print_format', 'json', - '-show_format', - '-show_streams', - inputPath - ]; - const result = await this.runProcess(this.ffprobePath, args); - const data = JSON.parse(result.stdout); - return { - format: { - filename: data.format.filename, - formatName: data.format.format_name, - formatLongName: data.format.format_long_name, - duration: parseFloat(data.format.duration) || 0, - size: parseInt(data.format.size, 10) || 0, - bitrate: parseInt(data.format.bit_rate, 10) || 0, - }, - streams: (data.streams || []).map((stream) => this.parseStreamInfo(stream)), - }; - } - /** - * Convert media file with specified options - */ - async convert(inputPath, outputPath, options = {}) { - const args = this.buildConversionArgs(inputPath, outputPath, options); - await this.runProcess(this.ffmpegPath, args); - } - /** - * Convert media file with progress reporting - */ - async convertWithProgress(inputPath, outputPath, options = {}, onProgress) { - // Get duration for progress percentage calculation - let totalDuration; - try { - const info = await this.getMediaInfo(inputPath); - totalDuration = info.format.duration; - } - catch { - // Continue without duration info - } - const args = ['-progress', 'pipe:1', ...this.buildConversionArgs(inputPath, outputPath, options)]; - return new Promise((resolve, reject) => { - const process = plugins.child_process.spawn(this.ffmpegPath, args); - let progressData = {}; - process.stdout?.on('data', (data) => { - const lines = data.toString().split('\n'); - for (const line of lines) { - const [key, value] = line.split('='); - if (!key || !value) - continue; - switch (key.trim()) { - case 'frame': - progressData.frame = parseInt(value, 10); - break; - case 'fps': - progressData.fps = parseFloat(value); - break; - case 'total_size': - progressData.size = parseInt(value, 10); - break; - case 'out_time_ms': - progressData.time = parseInt(value, 10) / 1000000; - if (totalDuration && progressData.time) { - progressData.percent = Math.min(100, (progressData.time / totalDuration) * 100); - } - break; - case 'bitrate': - progressData.bitrate = value.trim(); - break; - case 'speed': - progressData.speed = value.trim(); - break; - case 'progress': - if (value.trim() === 'continue' || value.trim() === 'end') { - if (onProgress && progressData.frame !== undefined) { - onProgress(progressData); - } - } - break; - } - } - }); - let stderr = ''; - process.stderr?.on('data', (data) => { - stderr += data.toString(); - }); - process.on('close', (code) => { - if (code === 0) { - resolve(); - } - else { - reject(new Error(`FFmpeg exited with code ${code}: ${stderr}`)); - } - }); - process.on('error', (err) => { - reject(err); - }); - }); - } - /** - * Extract audio from video file - */ - async extractAudio(inputPath, outputPath, options = {}) { - const conversionOptions = { - ...options, - noVideo: true, - }; - await this.convert(inputPath, outputPath, conversionOptions); - } - /** - * Remove audio from video file - */ - async removeAudio(inputPath, outputPath, options = {}) { - const conversionOptions = { - ...options, - noAudio: true, - }; - await this.convert(inputPath, outputPath, conversionOptions); - } - /** - * Take a screenshot at a specific time - */ - async screenshot(inputPath, outputPath, options) { - const args = [ - '-y', - '-ss', this.formatTime(options.time), - '-i', inputPath, - '-vframes', '1', - ]; - if (options.width || options.height) { - const scale = this.buildScaleFilter(options.width, options.height); - args.push('-vf', scale); - } - if (options.format === 'jpg' && options.quality) { - args.push('-q:v', String(Math.round((100 - options.quality) / 100 * 31))); - } - else if (options.format === 'webp' && options.quality) { - args.push('-quality', String(options.quality)); - } - args.push(outputPath); - await this.runProcess(this.ffmpegPath, args); - } - /** - * Generate multiple thumbnails from video - */ - async generateThumbnails(inputPath, outputDir, options) { - const info = await this.getMediaInfo(inputPath); - const duration = info.format.duration; - const interval = duration / (options.count + 1); - const pattern = options.filenamePattern || 'thumb_%d'; - const ext = options.format || 'png'; - const outputPaths = []; - for (let i = 1; i <= options.count; i++) { - const time = interval * i; - const filename = pattern.replace('%d', String(i).padStart(3, '0')) + '.' + ext; - const outputPath = plugins.path.join(outputDir, filename); - await this.screenshot(inputPath, outputPath, { - time, - width: options.width, - height: options.height, - format: options.format, - }); - outputPaths.push(outputPath); - } - return outputPaths; - } - /** - * Resize video - */ - async resize(inputPath, outputPath, width, height, options = {}) { - await this.convert(inputPath, outputPath, { ...options, width, height }); - } - /** - * Change video frame rate - */ - async changeFrameRate(inputPath, outputPath, fps, options = {}) { - await this.convert(inputPath, outputPath, { ...options, fps }); - } - /** - * Trim media file - */ - async trim(inputPath, outputPath, startTime, duration, options = {}) { - await this.convert(inputPath, outputPath, { ...options, startTime, duration }); - } - /** - * Convert to GIF - */ - async toGif(inputPath, outputPath, options = {}) { - const args = ['-y']; - if (options.startTime !== undefined) { - args.push('-ss', this.formatTime(options.startTime)); - } - args.push('-i', inputPath); - if (options.duration !== undefined) { - args.push('-t', this.formatTime(options.duration)); - } - // Build filter for GIF optimization - const filters = []; - if (options.fps) { - filters.push(`fps=${options.fps}`); - } - if (options.width || options.height) { - filters.push(this.buildScaleFilter(options.width, options.height)); - } - // Split filter for palette generation (better GIF quality) - filters.push('split[s0][s1]'); - filters.push('[s0]palettegen[p]'); - filters.push('[s1][p]paletteuse'); - args.push('-filter_complex', filters.join(',')); - args.push(outputPath); - await this.runProcess(this.ffmpegPath, args); - } - /** - * Concatenate multiple media files - */ - async concat(inputPaths, outputPath, options = {}) { - // Create concat file content - const concatContent = inputPaths - .map(p => `file '${p.replace(/'/g, "'\\''")}'`) - .join('\n'); - // Write to temp file - const tempFile = plugins.path.join(plugins.path.dirname(outputPath), `.concat_${Date.now()}.txt`); - // Write concat file using SmartFs - const fs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode()); - await fs.file(tempFile).write(concatContent); - try { - const args = [ - '-y', - '-f', 'concat', - '-safe', '0', - '-i', tempFile, - ]; - if (options.videoCodec) { - args.push('-c:v', options.videoCodec); - } - else { - args.push('-c', 'copy'); - } - if (options.audioCodec) { - args.push('-c:a', options.audioCodec); - } - args.push(outputPath); - await this.runProcess(this.ffmpegPath, args); - } - finally { - // Clean up temp file - await fs.file(tempFile).delete(); - } - } - /** - * Add audio to video - */ - async addAudio(videoPath, audioPath, outputPath, options = {}) { - const args = [ - '-y', - '-i', videoPath, - '-i', audioPath, - '-c:v', options.videoCodec || 'copy', - '-c:a', options.audioCodec || 'aac', - ]; - if (options.audioBitrate) { - args.push('-b:a', options.audioBitrate); - } - if (options.shortest) { - args.push('-shortest'); - } - args.push('-map', '0:v:0', '-map', '1:a:0'); - args.push(outputPath); - await this.runProcess(this.ffmpegPath, args); - } - /** - * Get available encoders - */ - async getEncoders() { - const result = await this.runProcess(this.ffmpegPath, ['-encoders', '-hide_banner']); - const lines = result.stdout.split('\n'); - const encoders = []; - let started = false; - for (const line of lines) { - if (line.includes('------')) { - started = true; - continue; - } - if (started && line.trim()) { - const match = line.match(/^\s*[A-Z.]+\s+(\S+)/); - if (match) { - encoders.push(match[1]); - } - } - } - return encoders; - } - /** - * Get available decoders - */ - async getDecoders() { - const result = await this.runProcess(this.ffmpegPath, ['-decoders', '-hide_banner']); - const lines = result.stdout.split('\n'); - const decoders = []; - let started = false; - for (const line of lines) { - if (line.includes('------')) { - started = true; - continue; - } - if (started && line.trim()) { - const match = line.match(/^\s*[A-Z.]+\s+(\S+)/); - if (match) { - decoders.push(match[1]); - } - } - } - return decoders; - } - /** - * Get available formats - */ - async getFormats() { - const result = await this.runProcess(this.ffmpegPath, ['-formats', '-hide_banner']); - const lines = result.stdout.split('\n'); - const formats = []; - let started = false; - for (const line of lines) { - if (line.includes('--')) { - started = true; - continue; - } - if (started && line.trim()) { - const match = line.match(/^\s*[DE ]+\s+(\S+)/); - if (match) { - formats.push(match[1]); - } - } - } - return formats; - } - /** - * Run ffmpeg with raw arguments - */ - async runRaw(args) { - return this.runProcess(this.ffmpegPath, args); - } - /** - * Run ffprobe with raw arguments - */ - async runProbeRaw(args) { - return this.runProcess(this.ffprobePath, args); - } - // ============ Private Methods ============ - buildConversionArgs(inputPath, outputPath, options) { - const args = []; - // Overwrite flag - if (options.overwrite !== false) { - args.push('-y'); - } - // Input seeking (before -i for fast seeking) - if (options.startTime !== undefined) { - args.push('-ss', this.formatTime(options.startTime)); - } - args.push('-i', inputPath); - // Duration (after -i) - if (options.duration !== undefined) { - args.push('-t', this.formatTime(options.duration)); - } - // Video options - if (options.noVideo) { - args.push('-vn'); - } - else { - if (options.videoCodec) { - args.push('-c:v', options.videoCodec); - } - if (options.videoBitrate) { - args.push('-b:v', options.videoBitrate); - } - if (options.crf !== undefined) { - args.push('-crf', String(options.crf)); - } - if (options.preset) { - args.push('-preset', options.preset); - } - if (options.fps) { - args.push('-r', String(options.fps)); - } - if (options.width || options.height) { - args.push('-vf', this.buildScaleFilter(options.width, options.height)); - } - } - // Audio options - if (options.noAudio) { - args.push('-an'); - } - else { - if (options.audioCodec) { - args.push('-c:a', options.audioCodec); - } - if (options.audioBitrate) { - args.push('-b:a', options.audioBitrate); - } - if (options.sampleRate) { - args.push('-ar', String(options.sampleRate)); - } - if (options.audioChannels) { - args.push('-ac', String(options.audioChannels)); - } - } - // Output format - if (options.format) { - args.push('-f', options.format); - } - // Extra arguments - if (options.extraArgs) { - args.push(...options.extraArgs); - } - args.push(outputPath); - return args; - } - buildScaleFilter(width, height) { - const w = width ? String(width) : '-1'; - const h = height ? String(height) : '-1'; - // Use -2 instead of -1 to ensure even dimensions (required for some codecs) - return `scale=${w === '-1' ? '-2' : w}:${h === '-1' ? '-2' : h}`; - } - formatTime(time) { - if (typeof time === 'string') { - return time; - } - // Convert seconds to HH:MM:SS.mmm format - const hours = Math.floor(time / 3600); - const minutes = Math.floor((time % 3600) / 60); - const seconds = time % 60; - return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toFixed(3).padStart(6, '0')}`; - } - parseStreamInfo(stream) { - const info = { - index: stream.index, - codecName: stream.codec_name, - codecLongName: stream.codec_long_name, - codecType: stream.codec_type, - }; - if (stream.codec_type === 'video') { - info.width = stream.width; - info.height = stream.height; - if (stream.r_frame_rate) { - const [num, den] = stream.r_frame_rate.split('/').map(Number); - info.frameRate = den ? num / den : num; - } - if (stream.bit_rate) { - info.bitrate = parseInt(stream.bit_rate, 10); - } - } - if (stream.codec_type === 'audio') { - info.sampleRate = parseInt(stream.sample_rate, 10); - info.channels = stream.channels; - if (stream.bit_rate) { - info.bitrate = parseInt(stream.bit_rate, 10); - } - } - if (stream.duration) { - info.duration = parseFloat(stream.duration); - } - return info; - } - runProcess(command, args) { - return new Promise((resolve, reject) => { - const process = plugins.child_process.spawn(command, args); - let stdout = ''; - let stderr = ''; - process.stdout?.on('data', (data) => { - stdout += data.toString(); - }); - process.stderr?.on('data', (data) => { - stderr += data.toString(); - }); - process.on('close', (code) => { - if (code === 0) { - resolve({ stdout, stderr }); - } - else { - reject(new Error(`Process exited with code ${code}: ${stderr}`)); - } - }); - process.on('error', (err) => { - reject(err); - }); - }); - } -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zbWFydGZmbXBlZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuc21hcnRmZm1wZWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFFeEMsT0FBTyxFQUFFLGFBQWEsRUFBeUMsTUFBTSw0QkFBNEIsQ0FBQztBQVNsRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0Q0c7QUFDSCxNQUFNLE9BQU8sV0FBVztJQUNkLFVBQVUsQ0FBUztJQUNuQixXQUFXLENBQVM7SUFFNUI7UUFDRSxJQUFJLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQztRQUMzQyxJQUFJLENBQUMsV0FBVyxHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztJQUMvQyxDQUFDO0lBRUQsd0RBQXdEO0lBRXhEOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILE1BQU07UUFDSixPQUFPLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7OztPQWdCRztJQUNILEtBQUssQ0FBQyxNQUFvQixFQUFFLE9BQXVCO1FBQ2pELE9BQU8sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVELHVEQUF1RDtJQUV2RDs7T0FFRztJQUNJLEtBQUssQ0FBQyxZQUFZLENBQUMsU0FBaUI7UUFDekMsTUFBTSxJQUFJLEdBQUc7WUFDWCxJQUFJLEVBQUUsT0FBTztZQUNiLGVBQWUsRUFBRSxNQUFNO1lBQ3ZCLGNBQWM7WUFDZCxlQUFlO1lBQ2YsU0FBUztTQUNWLENBQUM7UUFFRixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFD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 \ No newline at end of file diff --git a/dist_ts/index.d.ts b/dist_ts/index.d.ts deleted file mode 100644 index a461191..0000000 --- a/dist_ts/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './classes.smartffmpeg.js'; -export * from './classes.ffmpegcommand.js'; -export * from './interfaces.js'; diff --git a/dist_ts/index.js b/dist_ts/index.js deleted file mode 100644 index 0b984c6..0000000 --- a/dist_ts/index.js +++ /dev/null @@ -1,7 +0,0 @@ -// Export main class -export * from './classes.smartffmpeg.js'; -// Export builder command class -export * from './classes.ffmpegcommand.js'; -// Export interfaces and types -export * from './interfaces.js'; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxvQkFBb0I7QUFDcEIsY0FBYywwQkFBMEIsQ0FBQztBQUV6QywrQkFBK0I7QUFDL0IsY0FBYyw0QkFBNEIsQ0FBQztBQUUzQyw4QkFBOEI7QUFDOUIsY0FBYyxpQkFBaUIsQ0FBQyJ9 \ No newline at end of file diff --git a/dist_ts/interfaces.d.ts b/dist_ts/interfaces.d.ts deleted file mode 100644 index d023338..0000000 --- a/dist_ts/interfaces.d.ts +++ /dev/null @@ -1,138 +0,0 @@ -/** - * Video codec options - */ -export type TVideoCodec = 'libx264' | 'libx265' | 'libvpx' | 'libvpx-vp9' | 'libaom-av1' | 'mpeg4' | 'copy' | string; -/** - * Audio codec options - */ -export type TAudioCodec = 'aac' | 'libmp3lame' | 'libopus' | 'libvorbis' | 'flac' | 'pcm_s16le' | 'copy' | string; -/** - * Output format/container - */ -export type TOutputFormat = 'mp4' | 'webm' | 'mkv' | 'avi' | 'mov' | 'flv' | 'mp3' | 'wav' | 'ogg' | 'flac' | 'm4a' | 'gif' | string; -/** - * Preset for encoding speed/quality tradeoff - */ -export type TPreset = 'ultrafast' | 'superfast' | 'veryfast' | 'faster' | 'fast' | 'medium' | 'slow' | 'slower' | 'veryslow'; -/** - * Media information from ffprobe - */ -export interface IMediaInfo { - format: { - filename: string; - formatName: string; - formatLongName: string; - duration: number; - size: number; - bitrate: number; - }; - streams: IStreamInfo[]; -} -/** - * Stream information - */ -export interface IStreamInfo { - index: number; - codecName: string; - codecLongName: string; - codecType: 'video' | 'audio' | 'subtitle' | 'data'; - width?: number; - height?: number; - frameRate?: number; - bitrate?: number; - sampleRate?: number; - channels?: number; - duration?: number; -} -/** - * Conversion options - */ -export interface IConversionOptions { - /** Output format/container */ - format?: TOutputFormat; - /** Video codec */ - videoCodec?: TVideoCodec; - /** Audio codec */ - audioCodec?: TAudioCodec; - /** Video bitrate (e.g., '1M', '2000k') */ - videoBitrate?: string; - /** Audio bitrate (e.g., '128k', '320k') */ - audioBitrate?: string; - /** Output width (height auto-scaled if not specified) */ - width?: number; - /** Output height (width auto-scaled if not specified) */ - height?: number; - /** Frame rate */ - fps?: number; - /** Audio sample rate in Hz */ - sampleRate?: number; - /** Audio channels (1 for mono, 2 for stereo) */ - audioChannels?: number; - /** Encoding preset (speed/quality tradeoff) */ - preset?: TPreset; - /** Constant Rate Factor for quality (0-51, lower is better) */ - crf?: number; - /** Start time in seconds or timecode string */ - startTime?: number | string; - /** Duration in seconds or timecode string */ - duration?: number | string; - /** Remove audio track */ - noAudio?: boolean; - /** Remove video track */ - noVideo?: boolean; - /** Additional ffmpeg arguments */ - extraArgs?: string[]; - /** Overwrite output file if exists */ - overwrite?: boolean; -} -/** - * Progress information during conversion - */ -export interface IProgressInfo { - /** Current frame number */ - frame: number; - /** Frames per second being processed */ - fps: number; - /** Current quality metric */ - q: number; - /** Output file size so far */ - size: number; - /** Current time position in seconds */ - time: number; - /** Current bitrate */ - bitrate: string; - /** Processing speed (e.g., 1.5x realtime) */ - speed: string; - /** Progress percentage (0-100) if duration known */ - percent?: number; -} -/** - * Screenshot options - */ -export interface IScreenshotOptions { - /** Time position in seconds or timecode string */ - time: number | string; - /** Output width */ - width?: number; - /** Output height */ - height?: number; - /** Output format (default: 'png') */ - format?: 'png' | 'jpg' | 'webp'; - /** Quality for jpg/webp (1-100) */ - quality?: number; -} -/** - * Thumbnail generation options - */ -export interface IThumbnailOptions { - /** Number of thumbnails to generate */ - count: number; - /** Output width */ - width?: number; - /** Output height */ - height?: number; - /** Output format */ - format?: 'png' | 'jpg' | 'webp'; - /** Filename pattern (use %d for number) */ - filenamePattern?: string; -} diff --git a/dist_ts/interfaces.js b/dist_ts/interfaces.js deleted file mode 100644 index f1ddea1..0000000 --- a/dist_ts/interfaces.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2ludGVyZmFjZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9 \ No newline at end of file diff --git a/dist_ts/plugins.d.ts b/dist_ts/plugins.d.ts deleted file mode 100644 index a21b924..0000000 --- a/dist_ts/plugins.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as path from 'path'; -import * as child_process from 'child_process'; -export { path, child_process }; -import * as smartfs from '@push.rocks/smartfs'; -import * as smartpath from '@push.rocks/smartpath'; -import * as smartpromise from '@push.rocks/smartpromise'; -export { smartfs, smartpath, smartpromise }; -export declare const ffmpegBinaryPath: string; -export declare const ffprobeBinaryPath: string; diff --git a/dist_ts/plugins.js b/dist_ts/plugins.js deleted file mode 100644 index e583e19..0000000 --- a/dist_ts/plugins.js +++ /dev/null @@ -1,15 +0,0 @@ -// Node native modules -import * as path from 'path'; -import * as child_process from 'child_process'; -import { createRequire } from 'module'; -export { path, child_process }; -// @push.rocks scope -import * as smartfs from '@push.rocks/smartfs'; -import * as smartpath from '@push.rocks/smartpath'; -import * as smartpromise from '@push.rocks/smartpromise'; -export { smartfs, smartpath, smartpromise }; -// ffmpeg static binaries - use createRequire for CommonJS compatibility -const require = createRequire(import.meta.url); -export const ffmpegBinaryPath = require('ffmpeg-static'); -export const ffprobeBinaryPath = require('ffprobe-static').path; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3BsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsc0JBQXNCO0FBQ3RCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sS0FBSyxhQUFhLE1BQU0sZUFBZSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDdkMsT0FBTyxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQztBQUUvQixvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLE9BQU8sTUFBTSxxQkFBcUIsQ0FBQztBQUMvQyxPQUFPLEtBQUssU0FBUyxNQUFNLHVCQUF1QixDQUFDO0FBQ25ELE9BQU8sS0FBSyxZQUFZLE1BQU0sMEJBQTBCLENBQUM7QUFDekQsT0FBTyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLENBQUM7QUFFNUMsd0VBQXdFO0FBQ3hFLE1BQU0sT0FBTyxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQy9DLE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUFXLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUNqRSxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBVyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxJQUFJLENBQUMifQ== \ No newline at end of file