@boruto_vk7/stickengine 0.0.5 → 1.0.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.
@@ -0,0 +1,137 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { type AxiosRequestConfig } from 'axios';
3
+ export interface StickerMetadata {
4
+ pack?: string;
5
+ author?: string;
6
+ emojis?: string[];
7
+ id?: string;
8
+ }
9
+ export interface JimpOptions {
10
+ greyscale?: boolean;
11
+ invert?: boolean;
12
+ sepia?: boolean;
13
+ blur?: number;
14
+ /** -1 .. 1 */
15
+ brightness?: number;
16
+ /** -1 .. 1 */
17
+ contrast?: number;
18
+ circle?: boolean;
19
+ resize?: {
20
+ width: number;
21
+ height: number;
22
+ };
23
+ text?: {
24
+ content: string;
25
+ alignmentX?: number;
26
+ alignmentY?: number;
27
+ color?: 'WHITE' | 'BLACK';
28
+ stroke?: boolean;
29
+ };
30
+ }
31
+ export interface StickEngineOptions {
32
+ /** Convert output to WebP sticker (default true). */
33
+ webp?: boolean;
34
+ /** Static-image edits via Jimp. */
35
+ edit?: JimpOptions | boolean;
36
+ /** remove.bg API key (string or list). Static images only. */
37
+ transparent?: string | string[] | false;
38
+ metadata?: StickerMetadata;
39
+ /**
40
+ * Delete temp files when you call `clean()`.
41
+ * Default false so you can read the sticker path first.
42
+ */
43
+ autoClean?: boolean;
44
+ /** Animated sticker FPS (default 15). */
45
+ fps?: number;
46
+ /** WebP quality 1–100 for animated (default 75). */
47
+ quality?: number;
48
+ /** Max animated duration in seconds (default 6). */
49
+ maxDuration?: number;
50
+ /** Temp directory (default ./tmp_stickengine). */
51
+ tempDir?: string;
52
+ }
53
+ export type StickInput = string | Buffer;
54
+ export interface StickResult {
55
+ /** Absolute path to the final .webp */
56
+ path: string;
57
+ /** File as Buffer */
58
+ buffer: Buffer;
59
+ /** Base64 (no data: prefix) */
60
+ base64: string;
61
+ animated: boolean;
62
+ width: number;
63
+ height: number;
64
+ size: number;
65
+ }
66
+ export interface MediaInfo {
67
+ width: number;
68
+ height: number;
69
+ duration: number;
70
+ }
71
+ export declare function getBuffer(url: string, options?: AxiosRequestConfig): Promise<Buffer>;
72
+ /**
73
+ * WhatsApp sticker engine (static + animated WebP + EXIF pack metadata).
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * import StickEngine from '@boruto_vk7/stickengine';
78
+ *
79
+ * const sticker = await StickEngine.create('./cat.gif', {
80
+ * metadata: { pack: 'My Pack', author: 'Me' },
81
+ * });
82
+ * // sticker.buffer → send to WhatsApp
83
+ * // sticker.path → temp file path
84
+ * ```
85
+ */
86
+ export declare class StickEngine extends EventEmitter {
87
+ options: Required<Pick<StickEngineOptions, 'webp' | 'autoClean' | 'fps' | 'quality' | 'maxDuration'>> & StickEngineOptions;
88
+ private tempDir;
89
+ private queue;
90
+ private createdFiles;
91
+ constructor(options?: StickEngineOptions);
92
+ /**
93
+ * Create a sticker in one call. Returns path + buffer + base64.
94
+ */
95
+ static create(input: StickInput, options?: StickEngineOptions): Promise<StickResult>;
96
+ /**
97
+ * Create sticker and return only the Buffer (handy for bots).
98
+ */
99
+ static toBuffer(input: StickInput, options?: StickEngineOptions): Promise<Buffer>;
100
+ /**
101
+ * Create sticker and return base64 string.
102
+ */
103
+ static toBase64String(input: StickInput, options?: StickEngineOptions): Promise<string>;
104
+ /** Instance one-shot (uses constructor options). */
105
+ build(input: StickInput): Promise<StickResult>;
106
+ addFile(file: StickInput): this;
107
+ add(...files: StickInput[]): this;
108
+ /**
109
+ * Process the queue. Returns settled results with `value` = absolute path.
110
+ * Prefer `build()` / `StickEngine.create()` for a simpler API.
111
+ */
112
+ start(): Promise<PromiseSettledResult<string>[]>;
113
+ /** Delete tracked temp files. */
114
+ clean(): void;
115
+ private track;
116
+ private processFile;
117
+ private materializeInput;
118
+ /**
119
+ * Write WhatsApp sticker pack EXIF.
120
+ * Animated WebP MUST use muxAnim — save() throws on animations.
121
+ */
122
+ private addExif;
123
+ private detectAnimatedWebp;
124
+ private convertToWebp;
125
+ private applyJimpEdits;
126
+ private getMediaInfo;
127
+ static fileToBase64(filePath: string): string;
128
+ /** 96×96 tray icon WebP for sticker packs. */
129
+ createTrayIcon(input: StickInput): Promise<string>;
130
+ /** Text-only sticker (transparent 512×512). */
131
+ createTextSticker(text: string, options?: {
132
+ color?: 'WHITE' | 'BLACK';
133
+ background?: number | string;
134
+ }): Promise<StickResult>;
135
+ }
136
+ export default StickEngine;
137
+ //# sourceMappingURL=StickEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StickEngine.d.ts","sourceRoot":"","sources":["../../src/StickEngine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { StickEngine, getBuffer, type StickEngineOptions, type StickerMetadata, type JimpOptions, type StickInput, type StickResult, type MediaInfo, } from './StickEngine.js';
2
+ export { StickEngine as default } from './StickEngine.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
package/package.json CHANGED
@@ -1,50 +1,73 @@
1
1
  {
2
2
  "name": "@boruto_vk7/stickengine",
3
- "version": "0.0.5",
4
- "description": "StickEngine module for creating WhatsApp stickers",
3
+ "version": "1.0.0",
4
+ "description": "Simple WhatsApp sticker engine static & animated WebP, EXIF pack metadata, ESM + CommonJS.",
5
+ "author": "Borutovk7",
6
+ "contributors": [
7
+ "Eduh Dev"
8
+ ],
9
+ "license": "MIT",
10
+ "keywords": [
11
+ "whatsapp",
12
+ "sticker",
13
+ "webp",
14
+ "animated",
15
+ "stickengine",
16
+ "baileys",
17
+ "wbot"
18
+ ],
5
19
  "type": "module",
6
- "main": "dist/StickEngine.js",
7
- "module": "dist/StickEngine.js",
8
- "types": "dist/StickEngine.d.ts",
20
+ "main": "./dist/cjs/index.js",
21
+ "module": "./dist/esm/index.js",
22
+ "types": "./dist/types/index.d.ts",
9
23
  "exports": {
10
24
  ".": {
11
- "require": "./dist/StickEngine.js",
12
- "import": "./dist/StickEngine.js",
13
- "types": "./dist/StickEngine.d.ts"
14
- }
25
+ "types": "./dist/types/index.d.ts",
26
+ "import": "./dist/esm/index.js",
27
+ "require": "./dist/cjs/index.js",
28
+ "default": "./dist/esm/index.js"
29
+ },
30
+ "./package.json": "./package.json"
15
31
  },
32
+ "files": [
33
+ "dist",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
16
37
  "scripts": {
17
- "build": "tsc",
18
- "test": "echo \"Error: no test specified\" && exit 1"
38
+ "clean": "node ./scripts/clean.mjs",
39
+ "build:esm": "tsc -p tsconfig.esm.json && node ./scripts/fix-esm-dirname.mjs && node ./scripts/copy-assets.mjs esm",
40
+ "build:cjs": "tsc -p tsconfig.cjs.json && node ./scripts/copy-assets.mjs cjs && node ./scripts/write-cjs-package.mjs",
41
+ "build:types": "tsc -p tsconfig.types.json",
42
+ "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:types",
43
+ "prepublishOnly": "npm run build",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit"
45
+ },
46
+ "engines": {
47
+ "node": ">=18"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
19
51
  },
20
- "keywords": [
21
- "sticker",
22
- "whatsapp",
23
- "stickengine"
24
- ],
25
- "author": "Borutovk7 <https://github.com/Borutovk7>",
26
- "contributors": [
27
- "Eduh Dev",
28
- "Manus AI"
29
- ],
30
- "license": "ISC",
31
52
  "repository": {
32
53
  "type": "git",
33
- "url": "https://github.com/Borutovk7/StickEngine.git"
54
+ "url": "git+https://github.com/Borutovk7/StickEngine.git"
55
+ },
56
+ "bugs": {
57
+ "url": "https://github.com/Borutovk7/StickEngine/issues"
34
58
  },
59
+ "homepage": "https://github.com/Borutovk7/StickEngine#readme",
35
60
  "dependencies": {
36
61
  "axios": "^1.6.0",
37
- "file-type": "^16.5.3",
38
- "fluent-ffmpeg": "^2.1.2",
39
- "jimp": "^0.22.10",
40
- "node-fetch": "^2.6.1",
41
- "node-webpmux": "^1.0.7",
62
+ "file-type": "^16.5.4",
63
+ "fluent-ffmpeg": "^2.1.3",
64
+ "jimp": "^0.22.12",
65
+ "node-webpmux": "^3.1.7",
42
66
  "remove.bg": "^1.3.0"
43
67
  },
44
68
  "devDependencies": {
45
- "@types/fluent-ffmpeg": "^2.1.28",
46
- "@types/node": "^25.9.2",
47
- "@types/node-fetch": "2.6.1",
48
- "typescript": "^6.0.3"
69
+ "@types/fluent-ffmpeg": "^2.1.27",
70
+ "@types/node": "^20.14.0",
71
+ "typescript": "^5.5.4"
49
72
  }
50
73
  }
Binary file
Binary file
@@ -1,53 +0,0 @@
1
- import { AxiosRequestConfig } from 'axios';
2
- import { EventEmitter } from 'events';
3
- export interface StickerMetadata {
4
- pack?: string;
5
- author?: string;
6
- emojis?: string[];
7
- }
8
- export interface JimpOptions {
9
- greyscale?: boolean;
10
- invert?: boolean;
11
- sepia?: boolean;
12
- blur?: number;
13
- resize?: {
14
- width: number;
15
- height: number;
16
- };
17
- text?: {
18
- content: string;
19
- alignmentX?: number;
20
- alignmentY?: number;
21
- color?: string;
22
- };
23
- }
24
- export interface StickEngineOptions {
25
- webp?: boolean;
26
- edit?: JimpOptions | boolean;
27
- convert?: boolean;
28
- transparent?: string | string[] | false;
29
- metadata?: StickerMetadata;
30
- autoClean?: boolean;
31
- fps?: number;
32
- quality?: number;
33
- }
34
- /**
35
- * Faz GET em uma URL e retorna o corpo como Buffer.
36
- */
37
- export declare const getBuffer: (url: string, options?: AxiosRequestConfig) => Promise<Buffer>;
38
- export declare class StickEngine extends EventEmitter {
39
- options: StickEngineOptions;
40
- private tempDir;
41
- private queue;
42
- private createdFiles;
43
- constructor(options?: StickEngineOptions);
44
- addFile(file: string | Buffer): this;
45
- clean(): void;
46
- private processFile;
47
- private applyJimpEdits;
48
- private getMediaInfo;
49
- private convertToWebp;
50
- private addExif;
51
- start(): Promise<PromiseSettledResult<string>[]>;
52
- }
53
- export default StickEngine;
@@ -1,259 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import axios from 'axios';
4
- import { exec } from 'child_process';
5
- import { EventEmitter } from 'events';
6
- import webpMux from 'node-webpmux';
7
- import Jimp from 'jimp';
8
- import { removeBackgroundFromImageFile } from 'remove.bg';
9
- import { fileURLToPath } from 'url';
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = path.dirname(__filename);
13
-
14
- export const getBuffer = async (url, options = {}) => {
15
- try {
16
- const { data } = await axios({
17
- method: 'get',
18
- url,
19
- headers: {
20
- 'user-agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36',
21
- 'DNT': '1',
22
- 'Upgrade-Insecure-Request': '1',
23
- },
24
- ...options,
25
- responseType: 'arraybuffer',
26
- });
27
- return Buffer.from(data);
28
- }
29
- catch (err) {
30
- console.error(`Erro em getBuffer: ${err}`);
31
- const errorImagePath = path.join(__dirname, 'emror.jpg');
32
- if (fs.existsSync(errorImagePath)) {
33
- return fs.readFileSync(errorImagePath);
34
- }
35
- return Buffer.alloc(0);
36
- }
37
- };
38
-
39
- export class StickEngine extends EventEmitter {
40
- options;
41
- tempDir;
42
- queue;
43
- createdFiles;
44
-
45
- constructor(options = {}) {
46
- super();
47
- this.options = {
48
- webp: true,
49
- edit: false,
50
- convert: false,
51
- transparent: false,
52
- autoClean: true,
53
- fps: 15,
54
- quality: 80,
55
- metadata: {
56
- pack: 'StickEngine',
57
- author: 'Borutovk7 & Eduh Dev',
58
- emojis: ['🥶']
59
- },
60
- ...options
61
- };
62
- this.tempDir = path.join(process.cwd(), 'tmp_stickengine');
63
- if (!fs.existsSync(this.tempDir)) {
64
- fs.mkdirSync(this.tempDir, { recursive: true });
65
- }
66
- this.queue = [];
67
- this.createdFiles = [];
68
- }
69
-
70
- addFile(file) {
71
- this.queue.push(file);
72
- return this;
73
- }
74
-
75
- clean() {
76
- for (const file of this.createdFiles) {
77
- try {
78
- if (fs.existsSync(file)) {
79
- fs.unlinkSync(file);
80
- }
81
- }
82
- catch (err) {
83
- console.error(`Erro ao deletar arquivo temporário ${file}:`, err);
84
- }
85
- }
86
- this.createdFiles = [];
87
- }
88
-
89
- async processFile(input, index) {
90
- let filePath = '';
91
- let extension = '';
92
- const timestamp = Date.now();
93
- const localCreatedFiles = [];
94
- try {
95
- this.emit('st.start', { index, input });
96
- const ft = await import('file-type');
97
- const fileTypeFunc = ft.fromBuffer || ft.fileTypeFromBuffer || (ft.default && (ft.default.fromBuffer || ft.default.fileTypeFromBuffer));
98
-
99
- if (Buffer.isBuffer(input)) {
100
- const type = await fileTypeFunc(input);
101
- extension = type ? type.ext : 'bin';
102
- filePath = path.join(this.tempDir, `input_${timestamp}_${index}.${extension}`);
103
- fs.writeFileSync(filePath, input);
104
- localCreatedFiles.push(filePath);
105
- }
106
- else if (typeof input === 'string' && input.startsWith('http')) {
107
- const buffer = await getBuffer(input);
108
- const type = await fileTypeFunc(buffer);
109
- extension = type ? type.ext : 'bin';
110
- filePath = path.join(this.tempDir, `input_${timestamp}_${index}.${extension}`);
111
- fs.writeFileSync(filePath, buffer);
112
- localCreatedFiles.push(filePath);
113
- }
114
- else if (typeof input === 'string' && fs.existsSync(input)) {
115
- filePath = input;
116
- }
117
- else {
118
- throw new Error('Tipo de entrada inválido ou arquivo não encontrado.');
119
- }
120
-
121
- const mediaInfo = await this.getMediaInfo(filePath);
122
- this.emit('st.info', { index, ...mediaInfo });
123
- let currentFile = filePath;
124
- const isAnimated = mediaInfo.duration > 0 || extension === 'gif' || extension === 'mp4' || extension === 'webp';
125
-
126
- if (this.options.edit && !isAnimated) {
127
- const editedPath = path.join(this.tempDir, `edited_${timestamp}_${index}.png`);
128
- await this.applyJimpEdits(currentFile, editedPath, this.options.edit);
129
- localCreatedFiles.push(editedPath);
130
- currentFile = editedPath;
131
- }
132
-
133
- if (this.options.transparent && !isAnimated) {
134
- const apiKey = Array.isArray(this.options.transparent)
135
- ? this.options.transparent[Math.floor(Math.random() * this.options.transparent.length)]
136
- : this.options.transparent;
137
- if (typeof apiKey === 'string') {
138
- const bgRemovedPath = path.join(this.tempDir, `nobg_${timestamp}_${index}.png`);
139
- const result = await removeBackgroundFromImageFile({
140
- path: currentFile,
141
- apiKey,
142
- size: 'auto',
143
- type: 'auto'
144
- });
145
- fs.writeFileSync(bgRemovedPath, Buffer.from(result.base64img, 'base64'));
146
- localCreatedFiles.push(bgRemovedPath);
147
- currentFile = bgRemovedPath;
148
- }
149
- }
150
-
151
- const webpPath = path.join(this.tempDir, `sticker_${timestamp}_${index}.webp`);
152
- await this.convertToWebp(currentFile, webpPath, isAnimated);
153
- localCreatedFiles.push(webpPath);
154
- currentFile = webpPath;
155
-
156
- if (this.options.metadata) {
157
- await this.addExif(currentFile, this.options.metadata);
158
- }
159
-
160
- this.createdFiles.push(...localCreatedFiles);
161
- this.emit('st.data', { index, file: currentFile });
162
- return currentFile;
163
- }
164
- catch (error) {
165
- this.emit('st.error', { index, error: error.message });
166
- for (const f of localCreatedFiles) {
167
- if (fs.existsSync(f))
168
- fs.unlinkSync(f);
169
- }
170
- throw error;
171
- }
172
- }
173
-
174
- async applyJimpEdits(input, output, options) {
175
- const image = await Jimp.read(input);
176
- if (options.greyscale) image.greyscale();
177
- if (options.invert) image.invert();
178
- if (options.sepia) image.sepia();
179
- if (options.blur) image.blur(options.blur);
180
- if (options.resize) image.resize(options.resize.width, options.resize.height);
181
- if (options.text) {
182
- const font = await Jimp.loadFont(Jimp.FONT_SANS_32_WHITE);
183
- image.print(font, 0, 0, {
184
- text: options.text.content,
185
- alignmentX: options.text.alignmentX || Jimp.HORIZONTAL_ALIGN_CENTER,
186
- alignmentY: options.text.alignmentY || Jimp.VERTICAL_ALIGN_BOTTOM
187
- }, image.bitmap.width, image.bitmap.height);
188
- }
189
- await image.writeAsync(output);
190
- }
191
-
192
- getMediaInfo(file) {
193
- return new Promise((resolve) => {
194
- exec(`ffprobe -v error -select_streams v:0 -show_entries stream=width,height,duration -of csv=p=0:s=x "${file}"`, (err, stdout) => {
195
- if (err) return resolve({ width: 0, height: 0, duration: 0 });
196
- const parts = stdout.trim().split('x');
197
- resolve({
198
- width: parseInt(parts[0]) || 0,
199
- height: parseInt(parts[1]) || 0,
200
- duration: parseFloat(parts[2]) || 0
201
- });
202
- });
203
- });
204
- }
205
-
206
- convertToWebp(input, output, isAnimated) {
207
- return new Promise((resolve, reject) => {
208
- const fps = this.options.fps;
209
- const quality = this.options.quality;
210
- const scale = `scale=512:512:force_original_aspect_ratio=decrease,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,setsar=1`;
211
-
212
- let cmd;
213
- if (isAnimated) {
214
- cmd = `ffmpeg -y -i "${input}" -vcodec libwebp -vf "fps=${fps},${scale}" -lossless 0 -q:v ${quality} -loop 0 -preset default -an -vsync 0 -t 6 "${output}"`;
215
- } else {
216
- cmd = `ffmpeg -y -i "${input}" -vcodec libwebp -vf "${scale}" -lossless 1 -loop 0 -preset default -an -vsync 0 "${output}"`;
217
- }
218
-
219
- exec(cmd, (err, stdout, stderr) => {
220
- if (err) return reject(new Error(stderr || err.message));
221
- resolve();
222
- });
223
- });
224
- }
225
-
226
- async addExif(webpPath, metadata) {
227
- const json = {
228
- 'sticker-pack-id': 'StickEngine-Official',
229
- 'sticker-pack-name': metadata.pack || 'StickEngine',
230
- 'sticker-pack-publisher': metadata.author || 'Borutovk7',
231
- 'emojis': metadata.emojis || ['🥶']
232
- };
233
-
234
- const exifAttr = Buffer.from([0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x41, 0x57, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00]);
235
- const jsonBuff = Buffer.from(JSON.stringify(json), 'utf-8');
236
- const exifBuffer = Buffer.concat([exifAttr, jsonBuff]);
237
- exifBuffer.writeUIntLE(jsonBuff.length, 14, 4);
238
-
239
- const { Image } = webpMux;
240
- const img = new Image();
241
- await img.load(webpPath);
242
- img.exif = exifBuffer;
243
-
244
- if (img.hasAnim) {
245
- await img.muxAnim({ path: webpPath });
246
- } else {
247
- await Image.save(webpPath, img);
248
- }
249
- }
250
-
251
- async start() {
252
- if (this.queue.length === 0) throw new Error('Nenhum arquivo na fila.');
253
- const results = await Promise.allSettled(this.queue.map((file, i) => this.processFile(file, i)));
254
- this.queue = [];
255
- return results;
256
- }
257
- }
258
-
259
- export default StickEngine;