@twick/ffmpeg 0.11.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 motion-canvas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,26 @@
1
+ import type { FfmpegExporterOptions, RendererResult, RendererSettings } from '@twick/core';
2
+ export interface FFmpegExporterSettings extends RendererSettings {
3
+ fastStart: boolean;
4
+ includeAudio: boolean;
5
+ output: string;
6
+ }
7
+ export declare const extensions: Record<FfmpegExporterOptions['format'], string>;
8
+ /**
9
+ * The server-side implementation of the FFmpeg video exporter.
10
+ */
11
+ export declare class FFmpegExporterServer {
12
+ private readonly stream;
13
+ private readonly command;
14
+ private readonly promise;
15
+ private readonly settings;
16
+ private readonly jobFolder;
17
+ private readonly format;
18
+ constructor(settings: FFmpegExporterSettings);
19
+ start(): Promise<void>;
20
+ handleFrame({ data }: {
21
+ data: string;
22
+ }): Promise<void>;
23
+ end(result: RendererResult): Promise<void>;
24
+ kill(): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=ffmpeg-exporter-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg-exporter-server.d.ts","sourceRoot":"","sources":["../src/ffmpeg-exporter-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAQrB,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAItE,CAAC;AAEF;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;gBAEtC,QAAQ,EAAE,sBAAsB;IA4CtC,KAAK;IAIL,WAAW,CAAC,EAAC,IAAI,EAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC;IAKlC,GAAG,CAAC,MAAM,EAAE,cAAc;IAc1B,IAAI;CAQlB"}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FFmpegExporterServer = exports.extensions = void 0;
4
+ const telemetry_1 = require("@twick/telemetry");
5
+ const ffmpeg = require("fluent-ffmpeg");
6
+ const os = require("os");
7
+ const path = require("path");
8
+ const image_stream_1 = require("./image-stream");
9
+ const settings_1 = require("./settings");
10
+ const pixelFormats = {
11
+ mp4: 'yuv420p',
12
+ webm: 'yuva420p',
13
+ proRes: 'yuva444p10le',
14
+ };
15
+ exports.extensions = {
16
+ mp4: 'mp4',
17
+ webm: 'webm',
18
+ proRes: 'mov',
19
+ };
20
+ /**
21
+ * The server-side implementation of the FFmpeg video exporter.
22
+ */
23
+ class FFmpegExporterServer {
24
+ constructor(settings) {
25
+ if (settings.exporter.name !== '@twick/core/ffmpeg') {
26
+ throw new Error('Invalid exporter');
27
+ }
28
+ this.settings = settings;
29
+ this.format = settings.exporter.options.format;
30
+ this.jobFolder = path.join(os.tmpdir(), `twick-${this.settings.name}-${settings.hiddenFolderId}`);
31
+ this.stream = new image_stream_1.ImageStream();
32
+ ffmpeg.setFfmpegPath(settings_1.ffmpegSettings.getFfmpegPath());
33
+ this.command = ffmpeg();
34
+ // Input image sequence
35
+ this.command
36
+ .input(this.stream)
37
+ .inputFormat('image2pipe')
38
+ .inputFps(settings.fps);
39
+ // Output settings
40
+ const size = {
41
+ x: Math.round(settings.size.x * settings.resolutionScale),
42
+ y: Math.round(settings.size.y * settings.resolutionScale),
43
+ };
44
+ this.command
45
+ .output(path.join(this.jobFolder, `visuals.${exports.extensions[this.format]}`))
46
+ .outputOptions([`-pix_fmt ${pixelFormats[this.format]}`, '-shortest'])
47
+ .outputFps(settings.fps)
48
+ .size(`${size.x}x${size.y}`);
49
+ if (this.format === 'proRes') {
50
+ this.command.outputOptions(['-c:v prores_ks', '-profile:v 4444']);
51
+ }
52
+ this.command.outputOptions(['-movflags +faststart']);
53
+ this.promise = new Promise((resolve, reject) => {
54
+ this.command.on('end', resolve).on('error', reject);
55
+ });
56
+ }
57
+ async start() {
58
+ this.command.run();
59
+ }
60
+ async handleFrame({ data }) {
61
+ const base64Data = data.slice(data.indexOf(',') + 1);
62
+ this.stream.pushImage(Buffer.from(base64Data, 'base64'));
63
+ }
64
+ async end(result) {
65
+ this.stream.pushImage(null);
66
+ if (result === 1) {
67
+ try {
68
+ this.command.kill('SIGKILL');
69
+ await this.promise;
70
+ }
71
+ catch (err) {
72
+ (0, telemetry_1.sendEvent)(telemetry_1.EventName.Error, { message: err.message });
73
+ }
74
+ }
75
+ else {
76
+ await this.promise;
77
+ }
78
+ }
79
+ async kill() {
80
+ try {
81
+ this.command.kill('SIGKILL');
82
+ await this.promise;
83
+ }
84
+ catch (_) {
85
+ return;
86
+ }
87
+ }
88
+ }
89
+ exports.FFmpegExporterServer = FFmpegExporterServer;
90
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmZtcGVnLWV4cG9ydGVyLXNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9mZm1wZWctZXhwb3J0ZXItc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUtBLGdEQUFzRDtBQUN0RCx3Q0FBd0M7QUFDeEMseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3QixpREFBMkM7QUFDM0MseUNBQTBDO0FBUTFDLE1BQU0sWUFBWSxHQUFvRDtJQUNwRSxHQUFHLEVBQUUsU0FBUztJQUNkLElBQUksRUFBRSxVQUFVO0lBQ2hCLE1BQU0sRUFBRSxjQUFjO0NBQ3ZCLENBQUM7QUFFVyxRQUFBLFVBQVUsR0FBb0Q7SUFDekUsR0FBRyxFQUFFLEtBQUs7SUFDVixJQUFJLEVBQUUsTUFBTTtJQUNaLE1BQU0sRUFBRSxLQUFLO0NBQ2QsQ0FBQztBQUVGOztHQUVHO0FBQ0gsTUFBYSxvQkFBb0I7SUFRL0IsWUFBbUIsUUFBZ0M7UUFDakQsSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksS0FBSyxvQkFBb0IsRUFBRSxDQUFDO1lBQ3BELE1BQU0sSUFBSSxLQUFLLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBRUQsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLE1BQU0sR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFFL0MsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUN4QixFQUFFLENBQUMsTUFBTSxFQUFFLEVBQ1gsU0FBUyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksSUFBSSxRQUFRLENBQUMsY0FBYyxFQUFFLENBQ3pELENBQUM7UUFDRixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksMEJBQVcsRUFBRSxDQUFDO1FBRWhDLE1BQU0sQ0FBQyxhQUFhLENBQUMseUJBQWMsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFD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
@@ -0,0 +1,13 @@
1
+ import type { AssetInfo, FfmpegExporterOptions } from '@twick/core';
2
+ import type { AudioCodec } from './utils';
3
+ export declare const audioCodecs: Record<FfmpegExporterOptions['format'], AudioCodec>;
4
+ export declare function generateAudio({ outputDir, tempDir, assets, startFrame, endFrame, fps, }: {
5
+ outputDir: string;
6
+ tempDir: string;
7
+ assets: AssetInfo[][];
8
+ startFrame: number;
9
+ endFrame: number;
10
+ fps: number;
11
+ }): Promise<string[]>;
12
+ export declare function mergeMedia(outputFilename: string, outputDir: string, tempDir: string, format: FfmpegExporterOptions['format']): Promise<void>;
13
+ //# sourceMappingURL=generate-audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-audio.d.ts","sourceRoot":"","sources":["../src/generate-audio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,SAAS,EAAE,qBAAqB,EAAC,MAAM,aAAa,CAAC;AAOlE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,SAAS,CAAC;AASxC,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,UAAU,CAKzE,CAAC;AAkMJ,wBAAsB,aAAa,CAAC,EAClC,SAAS,EACT,OAAO,EACP,MAAM,EACN,UAAU,EACV,QAAQ,EACR,GAAG,GACJ,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,qBAkCA;AAED,wBAAsB,UAAU,CAC9B,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC,iBA6BxC"}
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.audioCodecs = void 0;
4
+ exports.generateAudio = generateAudio;
5
+ exports.mergeMedia = mergeMedia;
6
+ const ffmpeg = require("fluent-ffmpeg");
7
+ const fs = require("fs");
8
+ const os = require("os");
9
+ const path = require("path");
10
+ const ffmpeg_exporter_server_1 = require("./ffmpeg-exporter-server");
11
+ const settings_1 = require("./settings");
12
+ const utils_1 = require("./utils");
13
+ exports.audioCodecs = {
14
+ mp4: 'aac',
15
+ webm: 'libopus',
16
+ proRes: 'aac',
17
+ };
18
+ const SAMPLE_RATE = 48000;
19
+ function getAssetPlacement(frames) {
20
+ const assets = [];
21
+ // A map to keep track of the first and last currentTime for each asset.
22
+ const assetTimeMap = new Map();
23
+ for (let frame = 0; frame < frames.length; frame++) {
24
+ for (const asset of frames[frame]) {
25
+ if (!assetTimeMap.has(asset.key)) {
26
+ // If the asset is not in the map, add it with its current time as both start and end.
27
+ assetTimeMap.set(asset.key, {
28
+ start: asset.currentTime,
29
+ end: asset.currentTime,
30
+ });
31
+ assets.push({
32
+ key: asset.key,
33
+ src: asset.src,
34
+ type: asset.type,
35
+ startInVideo: frame,
36
+ endInVideo: frame,
37
+ duration: 0, // Placeholder, will be recalculated later based on frames
38
+ durationInSeconds: 0, // Placeholder, will be calculated based on currentTime
39
+ playbackRate: asset.playbackRate,
40
+ volume: asset.volume,
41
+ trimLeftInSeconds: asset.currentTime,
42
+ });
43
+ }
44
+ else {
45
+ // If the asset is already in the map, update the end time.
46
+ const timeInfo = assetTimeMap.get(asset.key);
47
+ if (timeInfo) {
48
+ timeInfo.end = asset.currentTime;
49
+ assetTimeMap.set(asset.key, timeInfo);
50
+ }
51
+ const existingAsset = assets.find(a => a.key === asset.key);
52
+ if (existingAsset) {
53
+ existingAsset.endInVideo = frame;
54
+ }
55
+ }
56
+ }
57
+ }
58
+ // Calculate the duration based on frame count and durationInSeconds based on currentTime.
59
+ assets.forEach(asset => {
60
+ const timeInfo = assetTimeMap.get(asset.key);
61
+ if (timeInfo) {
62
+ // Calculate durationInSeconds based on the start and end currentTime values.
63
+ asset.durationInSeconds =
64
+ (timeInfo.end - timeInfo.start) / asset.playbackRate;
65
+ }
66
+ // Recalculate the original duration based on frame count.
67
+ asset.duration = asset.endInVideo - asset.startInVideo + 1;
68
+ });
69
+ return assets;
70
+ }
71
+ function calculateAtempoFilters(playbackRate) {
72
+ const atempoFilters = [];
73
+ // Calculate how many times we need to 100x the speed
74
+ let rate = playbackRate;
75
+ while (rate > 100.0) {
76
+ atempoFilters.push('atempo=100.0');
77
+ rate /= 100.0;
78
+ }
79
+ // Add the last atempo filter with the remaining rate
80
+ if (rate > 1.0) {
81
+ atempoFilters.push(`atempo=${rate}`);
82
+ }
83
+ // Calculate how many times we need to halve the speed
84
+ rate = playbackRate;
85
+ while (rate < 0.5) {
86
+ atempoFilters.push('atempo=0.5');
87
+ rate *= 2.0;
88
+ }
89
+ // Add the last atempo filter with the remaining rate
90
+ if (rate < 1.0) {
91
+ atempoFilters.push(`atempo=${rate}`);
92
+ }
93
+ return atempoFilters;
94
+ }
95
+ async function prepareAudio(outputDir, tempDir, asset, startFrame, endFrame, fps) {
96
+ // Construct the output path
97
+ const sanitizedKey = asset.key.replace(/[/[\]]/g, '-');
98
+ const outputPath = path.join(tempDir, `${sanitizedKey}.wav`);
99
+ const trimLeft = asset.trimLeftInSeconds / asset.playbackRate;
100
+ const trimRight = 1 / fps +
101
+ Math.min(trimLeft + asset.durationInSeconds, trimLeft + (endFrame - startFrame) / fps);
102
+ const padStart = (asset.startInVideo / fps) * 1000;
103
+ const assetSampleRate = await (0, utils_1.getSampleRate)((0, utils_1.resolvePath)(outputDir, asset.src));
104
+ const padEnd = Math.max(0, (assetSampleRate * (endFrame - startFrame + 1)) / fps -
105
+ (assetSampleRate * asset.duration) / fps -
106
+ (assetSampleRate * padStart) / 1000);
107
+ const atempoFilters = calculateAtempoFilters(asset.playbackRate); // atempo filter value must be >=0.5 and <=100. If the value is higher or lower, this function sets multiple atempo filters
108
+ const resolvedPath = (0, utils_1.resolvePath)(outputDir, asset.src);
109
+ await new Promise((resolve, reject) => {
110
+ const audioFilters = [
111
+ ...atempoFilters,
112
+ `atrim=start=${trimLeft}:end=${trimRight}`,
113
+ `apad=pad_len=${padEnd}`,
114
+ `adelay=${padStart}|${padStart}|${padStart}`,
115
+ `volume=${asset.volume}`,
116
+ ].join(',');
117
+ ffmpeg.setFfmpegPath(settings_1.ffmpegSettings.getFfmpegPath());
118
+ ffmpeg(resolvedPath)
119
+ .audioChannels(2)
120
+ .audioCodec('pcm_s16le')
121
+ .audioFrequency(SAMPLE_RATE)
122
+ .outputOptions([`-af`, audioFilters])
123
+ .on('end', () => {
124
+ resolve();
125
+ })
126
+ .on('error', err => {
127
+ console.error(`Error processing audio for asset key: ${asset.key}`, err);
128
+ reject(err);
129
+ })
130
+ .save(outputPath);
131
+ });
132
+ return outputPath;
133
+ }
134
+ async function mergeAudioTracks(tempDir, audioFilenames) {
135
+ return new Promise((resolve, reject) => {
136
+ ffmpeg.setFfmpegPath(settings_1.ffmpegSettings.getFfmpegPath());
137
+ const command = ffmpeg();
138
+ audioFilenames.forEach(filename => {
139
+ command.input(filename);
140
+ });
141
+ command
142
+ .complexFilter([
143
+ `amix=inputs=${audioFilenames.length}:duration=longest,volume=${audioFilenames.length}`,
144
+ ])
145
+ .outputOptions(['-c:a', 'pcm_s16le'])
146
+ .on('end', () => {
147
+ resolve();
148
+ })
149
+ .on('error', err => {
150
+ console.error(`Error merging audio tracks: ${err.message}`);
151
+ reject(err);
152
+ })
153
+ .save(path.join(tempDir, `audio.wav`));
154
+ });
155
+ }
156
+ async function generateAudio({ outputDir, tempDir, assets, startFrame, endFrame, fps, }) {
157
+ const fullTempDir = path.join(os.tmpdir(), tempDir);
158
+ await (0, utils_1.makeSureFolderExists)(outputDir);
159
+ await (0, utils_1.makeSureFolderExists)(fullTempDir);
160
+ const assetPositions = getAssetPlacement(assets);
161
+ const audioFilenames = [];
162
+ for (const asset of assetPositions) {
163
+ let hasAudioStream = true;
164
+ if (asset.type !== 'audio') {
165
+ hasAudioStream = await (0, utils_1.checkForAudioStream)((0, utils_1.resolvePath)(outputDir, asset.src));
166
+ }
167
+ if (asset.playbackRate !== 0 && asset.volume !== 0 && hasAudioStream) {
168
+ const filename = await prepareAudio(outputDir, fullTempDir, asset, startFrame, endFrame, fps);
169
+ audioFilenames.push(filename);
170
+ }
171
+ }
172
+ if (audioFilenames.length > 0) {
173
+ await mergeAudioTracks(fullTempDir, audioFilenames);
174
+ }
175
+ return audioFilenames;
176
+ }
177
+ async function mergeMedia(outputFilename, outputDir, tempDir, format) {
178
+ const fullTempDir = path.join(os.tmpdir(), tempDir);
179
+ await (0, utils_1.makeSureFolderExists)(outputDir);
180
+ await (0, utils_1.makeSureFolderExists)(fullTempDir);
181
+ const audioWavExists = fs.existsSync(path.join(fullTempDir, `audio.wav`));
182
+ if (audioWavExists) {
183
+ await (0, utils_1.mergeAudioWithVideo)(path.join(fullTempDir, `audio.wav`), path.join(fullTempDir, `visuals.${ffmpeg_exporter_server_1.extensions[format]}`), path.join(outputDir, `${outputFilename}.${ffmpeg_exporter_server_1.extensions[format]}`), exports.audioCodecs[format]);
184
+ }
185
+ else {
186
+ const destination = path.join(outputDir, `${outputFilename}.${ffmpeg_exporter_server_1.extensions[format]}`);
187
+ await fs.promises.copyFile(path.join(fullTempDir, `visuals.${ffmpeg_exporter_server_1.extensions[format]}`), destination);
188
+ }
189
+ if (fullTempDir.endsWith('-undefined')) {
190
+ await fs.promises
191
+ .rm(fullTempDir, { recursive: true, force: true })
192
+ .catch(() => { });
193
+ }
194
+ }
195
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGUtYXVkaW8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZ2VuZXJhdGUtYXVkaW8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBdU5BLHNDQWdEQztBQUVELGdDQWlDQztBQXpTRCx3Q0FBd0M7QUFDeEMseUJBQXlCO0FBQ3pCLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IscUVBQW9EO0FBQ3BELHlDQUEwQztBQUUxQyxtQ0FNaUI7QUFFSixRQUFBLFdBQVcsR0FDdEI7SUFDRSxHQUFHLEVBQUUsS0FBSztJQUNWLElBQUksRUFBRSxTQUFTO0lBQ2YsTUFBTSxFQUFFLEtBQUs7Q0FDZCxDQUFDO0FBZUosTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDO0FBRTFCLFNBQVMsaUJBQWlCLENBQUMsTUFBcUI7SUFDOUMsTUFBTSxNQUFNLEdBQWlCLEVBQUUsQ0FBQztJQUVoQyx3RUFBd0U7SUFDeEUsTUFBTSxZQUFZLEdBQUcsSUFBSSxHQUFHLEVBQXdDLENBQUM7SUFFckUsS0FBSyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQztRQUNuRCxLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2xDLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNqQyxzRkFBc0Y7Z0JBQ3RGLFlBQVksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRTtvQkFDMUIsS0FBSyxFQUFFLEtBQUssQ0FBQyxXQUFXO29CQUN4QixHQUFHLEVBQUUsS0FBSyxDQUFDLFdBQVc7aUJBQ3ZCLENBQUMsQ0FBQztnQkFDSCxNQUFNLENBQUMsSUFBSSxDQUFDO29CQUNWLEdBQUcsRUFBRSxLQUFLLENBQUMsR0FBRztvQkFDZCxHQUFHLEVBQUUsS0FBSyxDQUFDLEdBQUc7b0JBQ2QsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO29CQUNoQixZQUFZLEVBQUUsS0FBSztvQkFDbkIsVUFBVSxFQUFFLEtBQUs7b0JBQ2pCLFFBQVEsRUFBRSxDQUFDLEVBQUUsMERBQTBEO29CQUN2RSxpQkFBaUIsRUFBRSxDQUFDLEVBQUUsdURBQXVEO29CQUM3RSxZQUFZLEVBQUUsS0FBSyxDQUFDLFlBQVk7b0JBQ2hDLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTTtvQkFDcEIsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLFdBQVc7aUJBQ3JDLENBQUMsQ0FBQztZQUNMLENBQUM7aUJBQU0sQ0FBQztnQkFDTiwyREFBMkQ7Z0JBQzNELE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUM3QyxJQUFJLFFBQVEsRUFBRSxDQUFDO29CQUNiLFFBQVEsQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQztvQkFDakMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUN4QyxDQUFDO2dCQUVELE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDNUQsSUFBSSxhQUFhLEVBQUUsQ0FBQztvQkFDbEIsYUFBYSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7Z0JBQ25DLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCwwRkFBMEY7SUFDMUYsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUNyQixNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM3QyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQ2IsNkVBQTZFO1lBQzdFLEtBQUssQ0FBQyxpQkFBaUI7Z0JBQ3JCLENBQUMsUUFBUSxDQUFDLEdBQUcsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQztRQUN6RCxDQUFDO1FBQ0QsMERBQTBEO1FBQzFELEtBQUssQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsWUFBWSxHQUFHLENBQUMsQ0FBQztJQUM3RCxDQUFDLENBQUMsQ0FBQztJQUVILE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRCxTQUFTLHNCQUFzQixDQUFDLFlBQW9CO0lBQ2xELE1BQU0sYUFBYSxHQUFHLEVBQUUsQ0FBQztJQUV6QixxREFBcUQ7SUFDckQsSUFBSSxJQUFJLEdBQUcsWUFBWSxDQUFDO0lBQ3hCLE9BQU8sSUFBSSxHQUFHLEtBQUssRUFBRSxDQUFDO1FBQ3BCLGFBQWEsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDbkMsSUFBSSxJQUFJLEtBQUssQ0FBQztJQUNoQixDQUFDO0lBQ0QscURBQXFEO0lBQ3JELElBQUksSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ2YsYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUVELHNEQUFzRDtJQUN0RCxJQUFJLEdBQUcsWUFBWSxDQUFDO0lBQ3BCLE9BQU8sSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDO1FBQ2xCLGFBQWEsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDakMsSUFBSSxJQUFJLEdBQUcsQ0FBQztJQUNkLENBQUM7SUFDRCxxREFBcUQ7SUFDckQsSUFBSSxJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUM7UUFDZixhQUFhLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQsT0FBTyxhQUFhLENBQUM7QUFDdkIsQ0FBQztBQUNELEtBQUssVUFBVSxZQUFZLENBQ3pCLFNBQWlCLEVBQ2pCLE9BQWUsRUFDZixLQUFpQixFQUNqQixVQUFrQixFQUNsQixRQUFnQixFQUNoQixHQUFXO0lBRVgsNEJBQTRCO0lBQzVCLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN2RCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxHQUFHLFlBQVksTUFBTSxDQUFDLENBQUM7SUFFN0QsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxZQUFZLENBQUM7SUFDOUQsTUFBTSxTQUFTLEdBQ2IsQ0FBQyxHQUFHLEdBQUc7UUFDUCxJQUFJLENBQUMsR0FBRyxDQUNOLFFBQVEsR0FBRyxLQUFLLENBQUMsaUJBQWlCLEVBQ2xDLFFBQVEsR0FBRyxDQUFDLFFBQVEsR0FBRyxVQUFVLENBQUMsR0FBRyxHQUFHLENBQ3pDLENBQUM7SUFDSixNQUFNLFFBQVEsR0FBRyxDQUFDLEtBQUssQ0FBQyxZQUFZLEdBQUcsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ25ELE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBQSxxQkFBYSxFQUN6QyxJQUFBLG1CQUFXLEVBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FDbEMsQ0FBQztJQUVGLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQ3JCLENBQUMsRUFDRCxDQUFDLGVBQWUsR0FBRyxDQUFDLFFBQVEsR0FBRyxVQUFVLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHO1FBQ25ELENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHO1FBQ3hDLENBQUMsZUFBZSxHQUFHLFFBQVEsQ0FBQyxHQUFHLElBQUksQ0FDdEMsQ0FBQztJQUVGLE1BQU0sYUFBYSxHQUFHLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLDJIQUEySDtJQUM3TCxNQUFNLFlBQVksR0FBRyxJQUFBLG1CQUFXLEVBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUV2RCxNQUFNLElBQUksT0FBTyxDQUFPLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQzFDLE1BQU0sWUFBWSxHQUFHO1lBQ25CLEdBQUcsYUFBYTtZQUNoQixlQUFlLFFBQVEsUUFBUSxTQUFTLEVBQUU7WUFDMUMsZ0JBQWdCLE1BQU0sRUFBRTtZQUN4QixVQUFVLFFBQVEsSUFBSSxRQUFRLElBQUksUUFBUSxFQUFFO1lBQzVDLFVBQVUsS0FBSyxDQUFDLE1BQU0sRUFBRTtTQUN6QixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUVaLE1BQU0sQ0FBQyxhQUFhLENBQUMseUJBQWMsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3JELE1BQU0sQ0FBQyxZQUFZLENBQUM7YUFDakIsYUFBYSxDQUFDLENBQUMsQ0FBQzthQUNoQixVQUFVLENBQUMsV0FBVyxDQUFDO2FBQ3ZCLGNBQWMsQ0FBQyxXQUFXLENBQUM7YUFDM0IsYUFBYSxDQUFDLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDO2FBQ3BDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFO1lBQ2QsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDLENBQUM7YUFDRCxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxFQUFFO1lBQ2pCLE9BQU8sQ0FBQyxLQUFLLENBQ1gseUNBQXlDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFDcEQsR0FBRyxDQUNKLENBQUM7WUFDRixNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDZCxDQUFDLENBQUM7YUFDRCxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDdEIsQ0FBQyxDQUFDLENBQUM7SUFFSCxPQUFPLFVBQVUsQ0FBQztBQUNwQixDQUFDO0FBRUQsS0FBSyxVQUFVLGdCQUFnQixDQUM3QixPQUFlLEVBQ2YsY0FBd0I7SUFFeEIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNyQyxNQUFNLENBQUMsYUFBYSxDQUFDLHlCQUFjLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUNyRCxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQztRQUV6QixjQUFjLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQ2hDLE9BQU8sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUIsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPO2FBQ0osYUFBYSxDQUFDO1lBQ2IsZUFBZSxjQUFjLENBQUMsTUFBTSw0QkFBNEIsY0FBYyxDQUFDLE1BQU0sRUFBRTtTQUN4RixDQUFDO2FBQ0QsYUFBYSxDQUFDLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxDQUFDO2FBQ3BDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFO1lBQ2QsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDLENBQUM7YUFDRCxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxFQUFFO1lBQ2pCLE9BQU8sQ0FBQyxLQUFLLENBQUMsK0JBQStCLEdBQUcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQzVELE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNkLENBQUMsQ0FBQzthQUNELElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQzNDLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVNLEtBQUssVUFBVSxhQUFhLENBQUMsRUFDbEMsU0FBUyxFQUNULE9BQU8sRUFDUCxNQUFNLEVBQ04sVUFBVSxFQUNWLFFBQVEsRUFDUixHQUFHLEdBUUo7SUFDQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUNwRCxNQUFNLElBQUEsNEJBQW9CLEVBQUMsU0FBUyxDQUFDLENBQUM7SUFDdEMsTUFBTSxJQUFBLDRCQUFvQixFQUFDLFdBQVcsQ0FBQyxDQUFDO0lBRXhDLE1BQU0sY0FBYyxHQUFHLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2pELE1BQU0sY0FBYyxHQUFhLEVBQUUsQ0FBQztJQUVwQyxLQUFLLE1BQU0sS0FBSyxJQUFJLGNBQWMsRUFBRSxDQUFDO1FBQ25DLElBQUksY0FBYyxHQUFHLElBQUksQ0FBQztRQUMxQixJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFLENBQUM7WUFDM0IsY0FBYyxHQUFHLE1BQU0sSUFBQSwyQkFBbUIsRUFDeEMsSUFBQSxtQkFBVyxFQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQ2xDLENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxLQUFLLENBQUMsWUFBWSxLQUFLLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUNyRSxNQUFNLFFBQVEsR0FBRyxNQUFNLFlBQVksQ0FDakMsU0FBUyxFQUNULFdBQVcsRUFDWCxLQUFLLEVBQ0wsVUFBVSxFQUNWLFFBQVEsRUFDUixHQUFHLENBQ0osQ0FBQztZQUNGLGNBQWMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDaEMsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLGNBQWMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDOUIsTUFBTSxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDdEQsQ0FBQztJQUVELE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUM7QUFFTSxLQUFLLFVBQVUsVUFBVSxDQUM5QixjQUFzQixFQUN0QixTQUFpQixFQUNqQixPQUFlLEVBQ2YsTUFBdUM7SUFFdkMsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDcEQsTUFBTSxJQUFBLDRCQUFvQixFQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3RDLE1BQU0sSUFBQSw0QkFBb0IsRUFBQyxXQUFXLENBQUMsQ0FBQztJQUV4QyxNQUFNLGNBQWMsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFDMUUsSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUNuQixNQUFNLElBQUEsMkJBQW1CLEVBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxFQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxXQUFXLG1DQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUN2RCxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxHQUFHLGNBQWMsSUFBSSxtQ0FBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFDL0QsbUJBQVcsQ0FBQyxNQUFNLENBQUMsQ0FDcEIsQ0FBQztJQUNKLENBQUM7U0FBTSxDQUFDO1FBQ04sTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FDM0IsU0FBUyxFQUNULEdBQUcsY0FBYyxJQUFJLG1DQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FDMUMsQ0FBQztRQUNGLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQ3hCLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLFdBQVcsbUNBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEVBQ3ZELFdBQVcsQ0FDWixDQUFDO0lBQ0osQ0FBQztJQUNELElBQUksV0FBVyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sRUFBRSxDQUFDLFFBQVE7YUFDZCxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFDLENBQUM7YUFDL0MsS0FBSyxDQUFDLEdBQUcsRUFBRSxHQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3JCLENBQUM7QUFDSCxDQUFDIn0=
@@ -0,0 +1,8 @@
1
+ import { Readable } from 'stream';
2
+ export declare class ImageStream extends Readable {
3
+ private image;
4
+ private hasData;
5
+ pushImage(image: Buffer | null): void;
6
+ _read(): void;
7
+ }
8
+ //# sourceMappingURL=image-stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-stream.d.ts","sourceRoot":"","sources":["../src/image-stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,QAAQ,CAAC;AAEhC,qBAAa,WAAY,SAAQ,QAAQ;IACvC,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,OAAO,CAAS;IAEjB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOrB,KAAK;CAMtB"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ImageStream = void 0;
4
+ const stream_1 = require("stream");
5
+ class ImageStream extends stream_1.Readable {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.image = null;
9
+ this.hasData = false;
10
+ }
11
+ pushImage(image) {
12
+ this.image = image;
13
+ this.hasData = true;
14
+ this._read();
15
+ }
16
+ // eslint-disable-next-line @typescript-eslint/naming-convention
17
+ _read() {
18
+ if (this.hasData) {
19
+ this.hasData = false;
20
+ this.push(this.image);
21
+ }
22
+ }
23
+ }
24
+ exports.ImageStream = ImageStream;
25
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2Utc3RyZWFtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ltYWdlLXN0cmVhbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxtQ0FBZ0M7QUFFaEMsTUFBYSxXQUFZLFNBQVEsaUJBQVE7SUFBekM7O1FBQ1UsVUFBSyxHQUFrQixJQUFJLENBQUM7UUFDNUIsWUFBTyxHQUFHLEtBQUssQ0FBQztJQWUxQixDQUFDO0lBYlEsU0FBUyxDQUFDLEtBQW9CO1FBQ25DLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO1FBQ3BCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNmLENBQUM7SUFFRCxnRUFBZ0U7SUFDaEQsS0FBSztRQUNuQixJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztZQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN4QixDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBakJELGtDQWlCQyJ9
@@ -0,0 +1,6 @@
1
+ export * from './ffmpeg-exporter-server';
2
+ export * from './generate-audio';
3
+ export * from './settings';
4
+ export * from './utils';
5
+ export * from './video-frame-extractor';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,yBAAyB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./ffmpeg-exporter-server"), exports);
18
+ __exportStar(require("./generate-audio"), exports);
19
+ __exportStar(require("./settings"), exports);
20
+ __exportStar(require("./utils"), exports);
21
+ __exportStar(require("./video-frame-extractor"), exports);
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDJEQUF5QztBQUN6QyxtREFBaUM7QUFDakMsNkNBQTJCO0FBQzNCLDBDQUF3QjtBQUN4QiwwREFBd0MifQ==
@@ -0,0 +1,22 @@
1
+ declare const ffmpegLogLevels: readonly ["quiet", "panic", "fatal", "error", "warning", "info", "verbose", "debug", "trace"];
2
+ export type LogLevel = (typeof ffmpegLogLevels)[number];
3
+ export type FfmpegSettings = {
4
+ ffmpegPath?: string;
5
+ ffprobePath?: string;
6
+ ffmpegLogLevel?: LogLevel;
7
+ };
8
+ declare class FfmpegSettingState {
9
+ private ffmpegPath;
10
+ private ffprobePath;
11
+ private logLevel;
12
+ constructor();
13
+ getFfmpegPath(): string;
14
+ setFfmpegPath(ffmpegPath: string): void;
15
+ getFfprobePath(): string;
16
+ setFfprobePath(ffprobePath: string): void;
17
+ getLogLevel(): "error" | "info" | "verbose" | "debug" | "warning" | "quiet" | "panic" | "fatal" | "trace";
18
+ setLogLevel(logLevel: LogLevel): void;
19
+ }
20
+ export declare const ffmpegSettings: FfmpegSettingState;
21
+ export {};
22
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,eAAe,+FAUX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,QAAQ,CAAC;CAC3B,CAAC;AAEF,cAAM,kBAAkB;IACtB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAW;;IA2BpB,aAAa;IAIb,aAAa,CAAC,UAAU,EAAE,MAAM;IAIhC,cAAc;IAId,cAAc,CAAC,WAAW,EAAE,MAAM;IAIlC,WAAW;IAIX,WAAW,CAAC,QAAQ,EAAE,QAAQ;CAGtC;AAED,eAAO,MAAM,cAAc,oBAA2B,CAAC"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ffmpegSettings = void 0;
4
+ const ffmpegInstaller = require("@ffmpeg-installer/ffmpeg");
5
+ const ffprobeInstaller = require("@ffprobe-installer/ffprobe");
6
+ const ffmpegLogLevels = [
7
+ 'quiet',
8
+ 'panic',
9
+ 'fatal',
10
+ 'error',
11
+ 'warning',
12
+ 'info',
13
+ 'verbose',
14
+ 'debug',
15
+ 'trace',
16
+ ];
17
+ class FfmpegSettingState {
18
+ constructor() {
19
+ this.ffmpegPath = ffmpegInstaller.path;
20
+ this.ffprobePath = ffprobeInstaller.path;
21
+ // Use the FFMPEG_PATH environment variable if it is set
22
+ if (process.env.FFMPEG_PATH) {
23
+ this.ffmpegPath = process.env.FFMPEG_PATH;
24
+ }
25
+ // Use the FFPROBE_PATH environment variable if it is set
26
+ if (process.env.FFPROBE_PATH) {
27
+ this.ffprobePath = process.env.FFPROBE_PATH;
28
+ }
29
+ this.logLevel = 'error';
30
+ // Use the FFMPEG_LOG_LEVEL environment variable if it is set
31
+ if (process.env.FFMPEG_LOG_LEVEL &&
32
+ ffmpegLogLevels.includes(process.env.FFMPEG_LOG_LEVEL)) {
33
+ this.logLevel = process.env.FFMPEG_LOG_LEVEL;
34
+ }
35
+ }
36
+ getFfmpegPath() {
37
+ return this.ffmpegPath;
38
+ }
39
+ setFfmpegPath(ffmpegPath) {
40
+ this.ffmpegPath = ffmpegPath;
41
+ }
42
+ getFfprobePath() {
43
+ return this.ffprobePath;
44
+ }
45
+ setFfprobePath(ffprobePath) {
46
+ this.ffprobePath = ffprobePath;
47
+ }
48
+ getLogLevel() {
49
+ return this.logLevel;
50
+ }
51
+ setLogLevel(logLevel) {
52
+ this.logLevel = logLevel;
53
+ }
54
+ }
55
+ exports.ffmpegSettings = new FfmpegSettingState();
56
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dGluZ3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc2V0dGluZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNERBQTREO0FBQzVELCtEQUErRDtBQUUvRCxNQUFNLGVBQWUsR0FBRztJQUN0QixPQUFPO0lBQ1AsT0FBTztJQUNQLE9BQU87SUFDUCxPQUFPO0lBQ1AsU0FBUztJQUNULE1BQU07SUFDTixTQUFTO0lBQ1QsT0FBTztJQUNQLE9BQU87Q0FDQyxDQUFDO0FBVVgsTUFBTSxrQkFBa0I7SUFLdEI7UUFDRSxJQUFJLENBQUMsVUFBVSxHQUFHLGVBQWUsQ0FBQyxJQUF5QixDQUFDO1FBQzVELElBQUksQ0FBQyxXQUFXLEdBQUcsZ0JBQWdCLENBQUMsSUFBeUIsQ0FBQztRQUU5RCx3REFBd0Q7UUFDeEQsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQzVCLElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUM7UUFDNUMsQ0FBQztRQUVELHlEQUF5RDtRQUN6RCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDN0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQztRQUM5QyxDQUFDO1FBRUQsSUFBSSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUM7UUFFeEIsNkRBQTZEO1FBQzdELElBQ0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0I7WUFDNUIsZUFBZSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUE0QixDQUFDLEVBQ2xFLENBQUM7WUFDRCxJQUFJLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQTRCLENBQUM7UUFDM0QsQ0FBQztJQUNILENBQUM7SUFFTSxhQUFhO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUN6QixDQUFDO0lBRU0sYUFBYSxDQUFDLFVBQWtCO1FBQ3JDLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFTSxjQUFjO1FBQ25CLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUMxQixDQUFDO0lBRU0sY0FBYyxDQUFDLFdBQW1CO1FBQ3ZDLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO0lBQ2pDLENBQUM7SUFFTSxXQUFXO1FBQ2hCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN2QixDQUFDO0lBRU0sV0FBVyxDQUFDLFFBQWtCO1FBQ25DLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7Q0FDRjtBQUVZLFFBQUEsY0FBYyxHQUFHLElBQUksa0JBQWtCLEVBQUUsQ0FBQyJ9