@boruto_vk7/stickengine 0.0.1-alpha → 0.0.3-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -82
- package/package.json +11 -4
- package/package.json.bak +0 -49
- package/src/StickEngine.ts +0 -221
- package/src/emror.jpg +0 -0
- package/tsconfig.json +0 -18
package/README.md
CHANGED
|
@@ -1,131 +1,135 @@
|
|
|
1
|
-
# StickEngine
|
|
1
|
+
# StickEngine
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@boruto_vk7/stickengine)
|
|
4
|
+
[](https://github.com/Borutovk7/StickEngine/blob/main/LICENSE)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
Módulo Node.js para criação de stickers para WhatsApp — feito pra funcionar em qualquer lugar, do **Termux no seu celular** até um servidor dedicado. Sem dependências nativas complicadas, sem dor de cabeça na instalação.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- **Metadados Personalizados (EXIF)**: Adiciona informações como nome do pacote, autor e emojis diretamente no sticker.
|
|
9
|
-
- **Suporte a URLs, Buffers e Caminhos Locais**: Flexibilidade na entrada de dados para a criação dos stickers.
|
|
10
|
-
- **Remoção de Fundo (Opcional)**: Integração com a API `remove.bg` para remover o fundo de imagens, ideal para criar stickers transparentes.
|
|
11
|
-
- **Compatibilidade CJS e ESM**: O módulo pode ser utilizado tanto em projetos CommonJS (`require`) quanto em módulos ES (`import`).
|
|
8
|
+
> Sabe aquele sofrimento de tentar rodar um módulo de sticker no Termux e quebrar tudo por causa do `sharp` ou de alguma lib nativa? O StickEngine foi criado exatamente pra resolver isso. Aqui funciona.
|
|
12
9
|
|
|
13
|
-
##
|
|
10
|
+
## Por que o StickEngine?
|
|
11
|
+
|
|
12
|
+
- ✅ **Funciona no Termux** — sem `sharp`, sem compilação nativa, sem erro de permissão
|
|
13
|
+
- ✅ **Funciona em VPS, Replit, Railway, servidor dedicado** — em qualquer ambiente
|
|
14
|
+
- ✅ **Zero configuração extra** — instala e já usa
|
|
15
|
+
- ✅ **Suporte a ESM e CJS** — compatível com qualquer projeto
|
|
16
|
+
- ✅ **Entrada flexível** — URL, Buffer ou caminho local, tanto faz
|
|
17
|
+
|
|
18
|
+
## Requisitos
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
- Node.js 16+
|
|
21
|
+
- [ffmpeg](https://ffmpeg.org/) instalado no sistema
|
|
16
22
|
|
|
17
23
|
```bash
|
|
18
|
-
#
|
|
19
|
-
|
|
24
|
+
# Termux
|
|
25
|
+
pkg install ffmpeg
|
|
20
26
|
|
|
21
|
-
#
|
|
22
|
-
|
|
23
|
-
sudo apt update && sudo apt install ffmpeg
|
|
24
|
-
# Para outras plataformas, consulte a documentação oficial do ffmpeg.
|
|
27
|
+
# Debian/Ubuntu/VPS
|
|
28
|
+
sudo apt install ffmpeg
|
|
25
29
|
```
|
|
26
30
|
|
|
27
|
-
##
|
|
31
|
+
## Instalação
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @boruto_vk7/stickengine
|
|
35
|
+
```
|
|
28
36
|
|
|
29
|
-
|
|
37
|
+
## Uso
|
|
30
38
|
|
|
31
|
-
###
|
|
39
|
+
### ESM
|
|
32
40
|
|
|
33
41
|
```javascript
|
|
34
|
-
import StickEngine from '
|
|
42
|
+
import StickEngine from '@boruto_vk7/stickengine';
|
|
35
43
|
|
|
36
44
|
const engine = new StickEngine({
|
|
37
45
|
metadata: {
|
|
38
46
|
pack: 'Meu Pack de Stickers',
|
|
39
|
-
author: 'Borutovk7
|
|
40
|
-
emojis: ['✨', '🚀']
|
|
47
|
+
author: 'Borutovk7',
|
|
48
|
+
emojis: ['✨', '🚀']
|
|
41
49
|
},
|
|
42
|
-
//
|
|
43
|
-
// transparent: ['
|
|
50
|
+
// Opcional: chaves da API remove.bg para remoção de fundo
|
|
51
|
+
// transparent: ['SUA_API_KEY']
|
|
44
52
|
});
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
engine.on('st.
|
|
48
|
-
engine.on('st.
|
|
49
|
-
engine.on('st.data', (data) => console.log(`[DATA] Sticker ${data.index} gerado em:`, data.file));
|
|
50
|
-
engine.on('st.error', (data) => console.error(`[ERROR] Falha no arquivo ${data.index}:`, data.error));
|
|
54
|
+
engine.on('st.start', (data) => console.log(`Processando:`, data.input));
|
|
55
|
+
engine.on('st.data', (data) => console.log(`Sticker gerado:`, data.file));
|
|
56
|
+
engine.on('st.error', (data) => console.error(`Erro:`, data.error));
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.start()
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
})
|
|
60
|
-
.catch(err => {
|
|
61
|
-
console.error('Ocorreu um erro geral no processamento:', err);
|
|
62
|
-
});
|
|
58
|
+
const results = await engine
|
|
59
|
+
.addFile('https://picsum.photos/512') // URL
|
|
60
|
+
.addFile('caminho/para/video.mp4') // caminho local
|
|
61
|
+
.addFile(buffer) // Buffer
|
|
62
|
+
.start();
|
|
63
|
+
|
|
64
|
+
console.log(results);
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
###
|
|
67
|
+
### CJS
|
|
66
68
|
|
|
67
69
|
```javascript
|
|
68
|
-
const StickEngine = require('
|
|
70
|
+
const StickEngine = require('@boruto_vk7/stickengine');
|
|
69
71
|
|
|
70
72
|
const engine = new StickEngine({
|
|
71
73
|
metadata: {
|
|
72
|
-
pack: 'Meu Pack
|
|
73
|
-
author: 'Borutovk7
|
|
74
|
+
pack: 'Meu Pack',
|
|
75
|
+
author: 'Borutovk7',
|
|
74
76
|
emojis: ['🎉']
|
|
75
77
|
}
|
|
76
78
|
});
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
engine.on('st.
|
|
80
|
-
|
|
80
|
+
engine.on('st.start', (data) => console.log(`Processando:`, data.input));
|
|
81
|
+
engine.on('st.data', (data) => console.log(`Sticker gerado:`, data.file));
|
|
82
|
+
engine.on('st.error', (data) => console.error(`Erro:`, data.error));
|
|
81
83
|
|
|
82
84
|
engine.addFile('https://picsum.photos/200')
|
|
83
85
|
.start()
|
|
84
|
-
.then(results =>
|
|
85
|
-
|
|
86
|
-
})
|
|
87
|
-
.catch(err => {
|
|
88
|
-
console.error('Ocorreu um erro geral no processamento CJS:', err);
|
|
89
|
-
});
|
|
86
|
+
.then(results => console.log(results))
|
|
87
|
+
.catch(err => console.error(err));
|
|
90
88
|
```
|
|
91
89
|
|
|
92
|
-
|
|
90
|
+
## Eventos
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
| Evento | Descrição |
|
|
93
|
+
|--------|-----------|
|
|
94
|
+
| `st.start` | Disparado ao iniciar o processamento de um arquivo |
|
|
95
|
+
| `st.info` | Metadados do arquivo sendo processado |
|
|
96
|
+
| `st.data` | Sticker gerado com sucesso |
|
|
97
|
+
| `st.error` | Erro ao processar um arquivo |
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
downloadAndProcess();
|
|
113
|
-
```
|
|
99
|
+
## API
|
|
100
|
+
|
|
101
|
+
### `new StickEngine(options)`
|
|
102
|
+
|
|
103
|
+
| Opção | Tipo | Descrição |
|
|
104
|
+
|-------|------|-----------|
|
|
105
|
+
| `metadata.pack` | `string` | Nome do pacote de stickers |
|
|
106
|
+
| `metadata.author` | `string` | Nome do autor |
|
|
107
|
+
| `metadata.emojis` | `string[]` | Emojis associados ao sticker |
|
|
108
|
+
| `transparent` | `string[]` | Chaves da API remove.bg para remoção de fundo |
|
|
109
|
+
|
|
110
|
+
### `.addFile(input)`
|
|
111
|
+
|
|
112
|
+
Adiciona um arquivo à fila. Aceita URL, Buffer ou caminho local. Retorna a instância para encadeamento.
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
### `.start()`
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
Inicia o processamento da fila. Retorna uma Promise com os resultados.
|
|
117
|
+
|
|
118
|
+
### `getBuffer(url)`
|
|
119
|
+
|
|
120
|
+
Utilitário para baixar uma URL como Buffer.
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
import { getBuffer } from '@boruto_vk7/stickengine';
|
|
124
|
+
|
|
125
|
+
const buffer = await getBuffer('https://example.com/image.png');
|
|
126
|
+
```
|
|
120
127
|
|
|
121
128
|
## Créditos
|
|
122
129
|
|
|
123
|
-
|
|
130
|
+
- [Eduh dev](https://github.com/Borutovk7)
|
|
124
131
|
|
|
125
|
-
- **Borutovk7** (GitHub: [Borutovk7](https://github.com/Borutovk7))
|
|
126
|
-
- **Eduh Dev**
|
|
127
|
-
- **Manus AI** (Adaptação e refatoração)
|
|
128
132
|
|
|
129
133
|
## Licença
|
|
130
134
|
|
|
131
|
-
|
|
135
|
+
ISC
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boruto_vk7/stickengine",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3-alpha",
|
|
4
4
|
"description": "StickEngine module for creating WhatsApp stickers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/StickEngine.js",
|
|
@@ -17,9 +17,16 @@
|
|
|
17
17
|
"build": "tsc",
|
|
18
18
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
19
19
|
},
|
|
20
|
-
"keywords": [
|
|
20
|
+
"keywords": [
|
|
21
|
+
"sticker",
|
|
22
|
+
"whatsapp",
|
|
23
|
+
"stickengine"
|
|
24
|
+
],
|
|
21
25
|
"author": "Borutovk7 <https://github.com/Borutovk7>",
|
|
22
|
-
"contributors": [
|
|
26
|
+
"contributors": [
|
|
27
|
+
"Eduh Dev",
|
|
28
|
+
"Manus AI"
|
|
29
|
+
],
|
|
23
30
|
"license": "ISC",
|
|
24
31
|
"repository": {
|
|
25
32
|
"type": "git",
|
|
@@ -40,4 +47,4 @@
|
|
|
40
47
|
"@types/node-fetch": "2.6.1",
|
|
41
48
|
"typescript": "^6.0.3"
|
|
42
49
|
}
|
|
43
|
-
}
|
|
50
|
+
}
|
package/package.json.bak
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@boruto_vk7/stickengine",
|
|
3
|
-
"version": "0.0.1-alpha",
|
|
4
|
-
"description": "StickEngine module for creating WhatsApp stickers",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/StickEngine.js",
|
|
7
|
-
"module": "dist/StickEngine.js",
|
|
8
|
-
"types": "dist/StickEngine.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"require": "./dist/StickEngine.js",
|
|
12
|
-
"import": "./dist/StickEngine.js",
|
|
13
|
-
"types": "./dist/StickEngine.d.ts"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"scripts": {
|
|
17
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
18
|
-
},
|
|
19
|
-
"keywords": [
|
|
20
|
-
"sticker",
|
|
21
|
-
"whatsapp",
|
|
22
|
-
"stickengine"
|
|
23
|
-
],
|
|
24
|
-
"author": "Borutovk7 <https://github.com/Borutovk7>",
|
|
25
|
-
"contributors": [
|
|
26
|
-
"Eduh Dev",
|
|
27
|
-
"Manus AI"
|
|
28
|
-
],
|
|
29
|
-
"license": "ISC",
|
|
30
|
-
"repository": {
|
|
31
|
-
"type": "git",
|
|
32
|
-
"url": "https://github.com/Borutovk7/StickEngine.git"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"axios": "^1.6.0",
|
|
36
|
-
"file-type": "^16.5.3",
|
|
37
|
-
"fluent-ffmpeg": "^2.1.2",
|
|
38
|
-
"jimp": "^0.22.10",
|
|
39
|
-
"node-fetch": "^2.6.1",
|
|
40
|
-
"node-webpmux": "^1.0.7",
|
|
41
|
-
"remove.bg": "^1.3.0"
|
|
42
|
-
},
|
|
43
|
-
"devDependencies": {
|
|
44
|
-
"@types/fluent-ffmpeg": "^2.1.28",
|
|
45
|
-
"@types/node": "^25.9.2",
|
|
46
|
-
"@types/node-fetch": "2.6.1",
|
|
47
|
-
"typescript": "^6.0.3"
|
|
48
|
-
}
|
|
49
|
-
}
|
package/src/StickEngine.ts
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import axios, { AxiosRequestConfig } from 'axios';
|
|
4
|
-
import { exec } from 'child_process';
|
|
5
|
-
import { EventEmitter } from 'events';
|
|
6
|
-
import ffmpeg from 'fluent-ffmpeg';
|
|
7
|
-
// @ts-ignore
|
|
8
|
-
import webpMux from 'node-webpmux';
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
import Jimp from 'jimp';
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
import { removeBackgroundFromImageFile } from 'remove.bg';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
-
const __dirname = path.dirname(__filename);
|
|
17
|
-
|
|
18
|
-
export interface StickerMetadata {
|
|
19
|
-
pack?: string;
|
|
20
|
-
author?: string;
|
|
21
|
-
emojis?: string[];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface StickEngineOptions {
|
|
25
|
-
webp?: boolean;
|
|
26
|
-
edit?: string | boolean;
|
|
27
|
-
convert?: boolean;
|
|
28
|
-
transparent?: string | string[] | false;
|
|
29
|
-
metadata?: StickerMetadata;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Faz GET em uma URL e retorna o corpo como Buffer.
|
|
34
|
-
* Fornecido pelo usuário para integração.
|
|
35
|
-
*/
|
|
36
|
-
export const getBuffer = async (url: string, options: AxiosRequestConfig = {}): Promise<Buffer> => {
|
|
37
|
-
try {
|
|
38
|
-
const { data } = await axios({
|
|
39
|
-
method: 'get',
|
|
40
|
-
url,
|
|
41
|
-
headers: {
|
|
42
|
-
'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',
|
|
43
|
-
'DNT': '1',
|
|
44
|
-
'Upgrade-Insecure-Request': '1',
|
|
45
|
-
},
|
|
46
|
-
...options,
|
|
47
|
-
responseType: 'arraybuffer',
|
|
48
|
-
});
|
|
49
|
-
return Buffer.from(data);
|
|
50
|
-
} catch (err) {
|
|
51
|
-
console.error(`Erro em getBuffer: ${err}`);
|
|
52
|
-
const errorImagePath = path.join(__dirname, 'src', 'emror.jpg');
|
|
53
|
-
if (fs.existsSync(errorImagePath)) {
|
|
54
|
-
return fs.readFileSync(errorImagePath);
|
|
55
|
-
}
|
|
56
|
-
return Buffer.alloc(0);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export class StickEngine extends EventEmitter {
|
|
61
|
-
public options: StickEngineOptions;
|
|
62
|
-
private tempDir: string;
|
|
63
|
-
private queue: any[];
|
|
64
|
-
|
|
65
|
-
constructor(options: StickEngineOptions = {}) {
|
|
66
|
-
super();
|
|
67
|
-
this.options = {
|
|
68
|
-
webp: true,
|
|
69
|
-
edit: false,
|
|
70
|
-
convert: false,
|
|
71
|
-
transparent: false,
|
|
72
|
-
metadata: {
|
|
73
|
-
pack: 'StickEngine',
|
|
74
|
-
author: 'Borutovk7 & Eduh Dev',
|
|
75
|
-
emojis: ['🥶']
|
|
76
|
-
},
|
|
77
|
-
...options
|
|
78
|
-
};
|
|
79
|
-
this.tempDir = path.join(process.cwd(), 'tmp_stickengine');
|
|
80
|
-
if (!fs.existsSync(this.tempDir)) {
|
|
81
|
-
fs.mkdirSync(this.tempDir, { recursive: true });
|
|
82
|
-
}
|
|
83
|
-
this.queue = [];
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
public addFile(file: string | Buffer): this {
|
|
87
|
-
this.queue.push(file);
|
|
88
|
-
return this;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private async processFile(input: string | Buffer, index: number): Promise<string> {
|
|
92
|
-
let filePath: string;
|
|
93
|
-
let extension: string;
|
|
94
|
-
const timestamp = Date.now();
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
this.emit('st.start', { index, input });
|
|
98
|
-
|
|
99
|
-
const ft = await import('file-type');
|
|
100
|
-
const fileTypeFunc = (ft as any).fromBuffer || (ft as any).fileTypeFromBuffer || (ft.default && ((ft.default as any).fromBuffer || (ft.default as any).fileTypeFromBuffer));
|
|
101
|
-
|
|
102
|
-
if (Buffer.isBuffer(input)) {
|
|
103
|
-
const type = await fileTypeFunc(input);
|
|
104
|
-
extension = type ? type.ext : 'bin';
|
|
105
|
-
filePath = path.join(this.tempDir, `input_${timestamp}_${index}.${extension}`);
|
|
106
|
-
fs.writeFileSync(filePath, input);
|
|
107
|
-
} else if (typeof input === 'string' && input.startsWith('http')) {
|
|
108
|
-
const buffer = await getBuffer(input);
|
|
109
|
-
const type = await fileTypeFunc(buffer);
|
|
110
|
-
extension = type ? type.ext : 'bin';
|
|
111
|
-
filePath = path.join(this.tempDir, `input_${timestamp}_${index}.${extension}`);
|
|
112
|
-
fs.writeFileSync(filePath, buffer);
|
|
113
|
-
} else if (typeof input === 'string' && fs.existsSync(input)) {
|
|
114
|
-
extension = path.extname(input).slice(1);
|
|
115
|
-
filePath = input;
|
|
116
|
-
} else {
|
|
117
|
-
throw new Error('Tipo de entrada inválido ou arquivo não encontrado.');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const metadata = await this.getMediaInfo(filePath);
|
|
121
|
-
this.emit('st.info', { index, ...metadata });
|
|
122
|
-
|
|
123
|
-
let currentFile = filePath;
|
|
124
|
-
|
|
125
|
-
if (this.options.transparent) {
|
|
126
|
-
const apiKey = Array.isArray(this.options.transparent)
|
|
127
|
-
? this.options.transparent[Math.floor(Math.random() * this.options.transparent.length)]
|
|
128
|
-
: this.options.transparent;
|
|
129
|
-
|
|
130
|
-
if (typeof apiKey === 'string') {
|
|
131
|
-
const bgRemovedPath = path.join(this.tempDir, `nobg_${timestamp}_${index}.png`);
|
|
132
|
-
const result = await removeBackgroundFromImageFile({
|
|
133
|
-
path: currentFile,
|
|
134
|
-
apiKey,
|
|
135
|
-
size: 'auto',
|
|
136
|
-
type: 'auto'
|
|
137
|
-
});
|
|
138
|
-
fs.writeFileSync(bgRemovedPath, Buffer.from(result.base64img, 'base64'));
|
|
139
|
-
currentFile = bgRemovedPath;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const webpPath = path.join(this.tempDir, `sticker_${timestamp}_${index}.webp`);
|
|
144
|
-
await this.convertToWebp(currentFile, webpPath);
|
|
145
|
-
currentFile = webpPath;
|
|
146
|
-
|
|
147
|
-
if (this.options.metadata) {
|
|
148
|
-
await this.addExif(currentFile, this.options.metadata);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.emit('st.data', { index, file: currentFile });
|
|
152
|
-
return currentFile;
|
|
153
|
-
|
|
154
|
-
} catch (error: any) {
|
|
155
|
-
this.emit('st.error', { index, error: error.message });
|
|
156
|
-
throw error;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
private getMediaInfo(file: string): Promise<any> {
|
|
161
|
-
return new Promise((resolve, reject) => {
|
|
162
|
-
exec(`ffprobe -v error -select_streams v:0 -show_entries stream=width,height,duration -of csv=p=0:s=x ${file}`, (err, stdout) => {
|
|
163
|
-
if (err) return reject(err);
|
|
164
|
-
const [width, height, duration] = stdout.split('x');
|
|
165
|
-
resolve({
|
|
166
|
-
width: parseInt(width) || 0,
|
|
167
|
-
height: parseInt(height) || 0,
|
|
168
|
-
duration: parseFloat(duration) || 0
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
private convertToWebp(input: string, output: string): Promise<void> {
|
|
175
|
-
return new Promise((resolve, reject) => {
|
|
176
|
-
ffmpeg(input)
|
|
177
|
-
.on('error', reject)
|
|
178
|
-
.on('end', () => resolve())
|
|
179
|
-
.addOutputOptions([
|
|
180
|
-
'-vcodec', 'libwebp',
|
|
181
|
-
'-vf', 'scale=512:512:force_original_aspect_ratio=decrease,fps=15,pad=512:512:(ow-iw)/2:(oh-ih)/2:color=#00000000,setsar=1',
|
|
182
|
-
'-lossless', '1',
|
|
183
|
-
'-loop', '0',
|
|
184
|
-
'-preset', 'default',
|
|
185
|
-
'-an',
|
|
186
|
-
'-vsync', '0'
|
|
187
|
-
])
|
|
188
|
-
.toFormat('webp')
|
|
189
|
-
.save(output);
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private async addExif(webpPath: string, metadata: StickerMetadata): Promise<void> {
|
|
194
|
-
const json = {
|
|
195
|
-
'sticker-pack-id': 'StickEngine-Manus',
|
|
196
|
-
'sticker-pack-name': metadata.pack || 'StickEngine',
|
|
197
|
-
'sticker-pack-publisher': metadata.author || 'Borutovk7 & Eduh Dev',
|
|
198
|
-
'emojis': metadata.emojis || ['🥶']
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const Image = webpMux.Image || (webpMux.default && webpMux.default.Image);
|
|
202
|
-
const img = new Image();
|
|
203
|
-
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]);
|
|
204
|
-
const jsonBuff = Buffer.from(JSON.stringify(json), 'utf-8');
|
|
205
|
-
const exifBuffer = Buffer.concat([exifAttr, jsonBuff]);
|
|
206
|
-
exifBuffer.writeUIntLE(jsonBuff.length, 14, 4);
|
|
207
|
-
|
|
208
|
-
await img.load(webpPath);
|
|
209
|
-
img.exif = exifBuffer;
|
|
210
|
-
await img.save(webpPath);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
public async start(): Promise<PromiseSettledResult<string>[]> {
|
|
214
|
-
if (this.queue.length === 0) throw new Error('Nenhum arquivo na fila.');
|
|
215
|
-
const results = await Promise.allSettled(this.queue.map((file, i) => this.processFile(file, i)));
|
|
216
|
-
this.queue = [];
|
|
217
|
-
return results;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export default StickEngine;
|
package/src/emror.jpg
DELETED
|
File without changes
|
package/tsconfig.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"declaration": true,
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"rootDir": "./src",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"skipLibCheck": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"allowJs": true,
|
|
14
|
-
"resolveJsonModule": true
|
|
15
|
-
},
|
|
16
|
-
"include": ["src/**/*"],
|
|
17
|
-
"exclude": ["node_modules", "dist"]
|
|
18
|
-
}
|