n8n-nodes-sotoros-gotenberg 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.
- package/README.md +123 -0
- package/README.ru.md +123 -0
- package/dist/Gotenberg.node.d.ts +5 -0
- package/dist/Gotenberg.node.js +337 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/nodes/Gotenberg/gotenberg.svg +8 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# n8n-nodes-gotenberg
|
|
2
|
+
|
|
3
|
+
Custom n8n node for integrating with Gotenberg API to convert documents to PDF.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Convert Office documents (Word, Excel, PowerPoint) to PDF
|
|
8
|
+
- Convert HTML to PDF
|
|
9
|
+
- Convert Markdown to PDF
|
|
10
|
+
- Convert URLs to PDF
|
|
11
|
+
- Merge multiple PDF files
|
|
12
|
+
- Support for single binary files and arrays of binary files
|
|
13
|
+
- Automatic processing of all binary properties from previous nodes
|
|
14
|
+
- Configurable conversion options (landscape, page ranges, scale, etc.)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
1. Clone this repository or copy the files to your n8n custom nodes directory
|
|
19
|
+
2. Install dependencies:
|
|
20
|
+
```bash
|
|
21
|
+
npm install
|
|
22
|
+
```
|
|
23
|
+
3. Build the project:
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
```
|
|
27
|
+
4. Copy the `dist` folder to your n8n custom nodes directory, or install it as a package
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
### Gotenberg URL
|
|
32
|
+
The base URL of your Gotenberg server (default: `http://localhost:3000`)
|
|
33
|
+
|
|
34
|
+
### Operation
|
|
35
|
+
Select the type of conversion:
|
|
36
|
+
- **Convert Office Documents**: Convert Word, Excel, PowerPoint files to PDF
|
|
37
|
+
- **Convert HTML**: Convert HTML content to PDF
|
|
38
|
+
- **Convert Markdown**: Convert Markdown content to PDF
|
|
39
|
+
- **Convert URL**: Convert a web page URL to PDF
|
|
40
|
+
- **Merge PDFs**: Merge multiple PDF files into one
|
|
41
|
+
|
|
42
|
+
### Binary Property
|
|
43
|
+
Name of the binary property containing the file(s) to convert. If left empty, all binary properties from the previous node will be processed automatically.
|
|
44
|
+
|
|
45
|
+
### Output Binary Property
|
|
46
|
+
Name of the binary property where the converted PDF will be saved (default: `data`)
|
|
47
|
+
|
|
48
|
+
### Options
|
|
49
|
+
- **Landscape**: Use landscape orientation
|
|
50
|
+
- **Page Ranges**: Specify page ranges (e.g., "1-2,4-5")
|
|
51
|
+
- **Scale**: Scale factor for the PDF (0.1 to 2)
|
|
52
|
+
- **Wait Timeout**: Maximum time to wait for conversion (e.g., "30s", "1m")
|
|
53
|
+
- **Wait Delay**: Delay before starting conversion (e.g., "1s")
|
|
54
|
+
|
|
55
|
+
## Usage Examples
|
|
56
|
+
|
|
57
|
+
### Example 1: Convert a single Office document
|
|
58
|
+
|
|
59
|
+
1. Use a node that reads a file (e.g., "Read Binary File")
|
|
60
|
+
2. Connect it to the Gotenberg node
|
|
61
|
+
3. Configure:
|
|
62
|
+
- Operation: "Convert Office Documents"
|
|
63
|
+
- Binary Property: (leave empty to use all binary properties)
|
|
64
|
+
- Gotenberg URL: Your Gotenberg server URL
|
|
65
|
+
|
|
66
|
+
### Example 2: Convert multiple files from an array
|
|
67
|
+
|
|
68
|
+
1. Use a node that returns multiple binary files (e.g., "Read Binary Files" with multiple files)
|
|
69
|
+
2. The Gotenberg node will automatically process all files in the array
|
|
70
|
+
3. All files will be converted and merged into a single PDF
|
|
71
|
+
|
|
72
|
+
### Example 3: Convert HTML to PDF
|
|
73
|
+
|
|
74
|
+
1. Use a node that provides HTML content as binary data
|
|
75
|
+
2. Configure:
|
|
76
|
+
- Operation: "Convert HTML"
|
|
77
|
+
- Binary Property: Name of the property containing HTML
|
|
78
|
+
|
|
79
|
+
## Binary Data Handling
|
|
80
|
+
|
|
81
|
+
The node supports both single binary files and arrays of binary files:
|
|
82
|
+
|
|
83
|
+
- **Single file**: If a binary property contains a single file, it will be processed directly
|
|
84
|
+
- **Array of files**: If a binary property contains an array of files, all files will be processed and sent to Gotenberg
|
|
85
|
+
- **Multiple properties**: If no specific binary property is specified, all binary properties from the previous node will be processed
|
|
86
|
+
|
|
87
|
+
## Requirements
|
|
88
|
+
|
|
89
|
+
- n8n (self-hosted or cloud)
|
|
90
|
+
- Gotenberg server running and accessible
|
|
91
|
+
- Node.js 18+ and npm
|
|
92
|
+
|
|
93
|
+
## Development
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Install dependencies
|
|
97
|
+
npm install
|
|
98
|
+
|
|
99
|
+
# Build the project
|
|
100
|
+
npm run build
|
|
101
|
+
|
|
102
|
+
# Watch mode for development
|
|
103
|
+
npm run dev
|
|
104
|
+
|
|
105
|
+
# Lint code
|
|
106
|
+
npm run lint
|
|
107
|
+
|
|
108
|
+
# Format code
|
|
109
|
+
npm run format
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
|
115
|
+
|
|
116
|
+
## Author
|
|
117
|
+
|
|
118
|
+
Danila Fokin <sir.sotoros@ys.ru>
|
|
119
|
+
|
|
120
|
+
## Links
|
|
121
|
+
|
|
122
|
+
- [Gotenberg Documentation](https://gotenberg.dev/)
|
|
123
|
+
- [n8n Documentation](https://docs.n8n.io/)
|
package/README.ru.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# n8n-nodes-sotoros-gotenberg
|
|
2
|
+
|
|
3
|
+
Кастомный узел n8n для интеграции с API Gotenberg для конвертации документов в PDF.
|
|
4
|
+
|
|
5
|
+
## Возможности
|
|
6
|
+
|
|
7
|
+
- Конвертация документов Office (Word, Excel, PowerPoint) в PDF
|
|
8
|
+
- Конвертация HTML в PDF
|
|
9
|
+
- Конвертация Markdown в PDF
|
|
10
|
+
- Конвертация URL в PDF
|
|
11
|
+
- Объединение нескольких PDF файлов
|
|
12
|
+
- Поддержка одиночных бинарных файлов и массивов бинарных файлов
|
|
13
|
+
- Автоматическая обработка всех бинарных свойств из предыдущих узлов
|
|
14
|
+
- Настраиваемые опции конвертации (альбомная ориентация, диапазоны страниц, масштаб и т.д.)
|
|
15
|
+
|
|
16
|
+
## Установка
|
|
17
|
+
|
|
18
|
+
1. Клонируйте этот репозиторий или скопируйте файлы в директорию кастомных узлов n8n
|
|
19
|
+
2. Установите зависимости:
|
|
20
|
+
```bash
|
|
21
|
+
npm install
|
|
22
|
+
```
|
|
23
|
+
3. Соберите проект:
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
```
|
|
27
|
+
4. Скопируйте папку `dist` в директорию кастомных узлов n8n, или установите как пакет
|
|
28
|
+
|
|
29
|
+
## Конфигурация
|
|
30
|
+
|
|
31
|
+
### Gotenberg URL
|
|
32
|
+
Базовый URL вашего сервера Gotenberg (по умолчанию: `http://localhost:3000`)
|
|
33
|
+
|
|
34
|
+
### Операция
|
|
35
|
+
Выберите тип конвертации:
|
|
36
|
+
- **Convert Office Documents**: Конвертация файлов Word, Excel, PowerPoint в PDF
|
|
37
|
+
- **Convert HTML**: Конвертация HTML контента в PDF
|
|
38
|
+
- **Convert Markdown**: Конвертация Markdown контента в PDF
|
|
39
|
+
- **Convert URL**: Конвертация веб-страницы по URL в PDF
|
|
40
|
+
- **Merge PDFs**: Объединение нескольких PDF файлов в один
|
|
41
|
+
|
|
42
|
+
### Binary Property
|
|
43
|
+
Имя бинарного свойства, содержащего файл(ы) для конвертации. Если оставить пустым, будут автоматически обработаны все бинарные свойства из предыдущего узла.
|
|
44
|
+
|
|
45
|
+
### Output Binary Property
|
|
46
|
+
Имя бинарного свойства, в которое будет сохранен сконвертированный PDF (по умолчанию: `data`)
|
|
47
|
+
|
|
48
|
+
### Опции
|
|
49
|
+
- **Landscape**: Использовать альбомную ориентацию
|
|
50
|
+
- **Page Ranges**: Указать диапазоны страниц (например, "1-2,4-5")
|
|
51
|
+
- **Scale**: Коэффициент масштабирования для PDF (от 0.1 до 2)
|
|
52
|
+
- **Wait Timeout**: Максимальное время ожидания конвертации (например, "30s", "1m")
|
|
53
|
+
- **Wait Delay**: Задержка перед началом конвертации (например, "1s")
|
|
54
|
+
|
|
55
|
+
## Примеры использования
|
|
56
|
+
|
|
57
|
+
### Пример 1: Конвертация одного документа Office
|
|
58
|
+
|
|
59
|
+
1. Используйте узел, который читает файл (например, "Read Binary File")
|
|
60
|
+
2. Подключите его к узлу Gotenberg
|
|
61
|
+
3. Настройте:
|
|
62
|
+
- Operation: "Convert Office Documents"
|
|
63
|
+
- Binary Property: (оставьте пустым для использования всех бинарных свойств)
|
|
64
|
+
- Gotenberg URL: URL вашего сервера Gotenberg
|
|
65
|
+
|
|
66
|
+
### Пример 2: Конвертация нескольких файлов из массива
|
|
67
|
+
|
|
68
|
+
1. Используйте узел, который возвращает несколько бинарных файлов (например, "Read Binary Files" с несколькими файлами)
|
|
69
|
+
2. Узел Gotenberg автоматически обработает все файлы в массиве
|
|
70
|
+
3. Все файлы будут сконвертированы и объединены в один PDF
|
|
71
|
+
|
|
72
|
+
### Пример 3: Конвертация HTML в PDF
|
|
73
|
+
|
|
74
|
+
1. Используйте узел, который предоставляет HTML контент как бинарные данные
|
|
75
|
+
2. Настройте:
|
|
76
|
+
- Operation: "Convert HTML"
|
|
77
|
+
- Binary Property: Имя свойства, содержащего HTML
|
|
78
|
+
|
|
79
|
+
## Обработка бинарных данных
|
|
80
|
+
|
|
81
|
+
Узел поддерживает как одиночные бинарные файлы, так и массивы бинарных файлов:
|
|
82
|
+
|
|
83
|
+
- **Одиночный файл**: Если бинарное свойство содержит один файл, он будет обработан напрямую
|
|
84
|
+
- **Массив файлов**: Если бинарное свойство содержит массив файлов, все файлы будут обработаны и отправлены в Gotenberg
|
|
85
|
+
- **Несколько свойств**: Если конкретное бинарное свойство не указано, будут обработаны все бинарные свойства из предыдущего узла
|
|
86
|
+
|
|
87
|
+
## Требования
|
|
88
|
+
|
|
89
|
+
- n8n (self-hosted или cloud)
|
|
90
|
+
- Работающий и доступный сервер Gotenberg
|
|
91
|
+
- Node.js 18+ и npm
|
|
92
|
+
|
|
93
|
+
## Разработка
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Установка зависимостей
|
|
97
|
+
npm install
|
|
98
|
+
|
|
99
|
+
# Сборка проекта
|
|
100
|
+
npm run build
|
|
101
|
+
|
|
102
|
+
# Режим наблюдения для разработки
|
|
103
|
+
npm run dev
|
|
104
|
+
|
|
105
|
+
# Проверка кода линтером
|
|
106
|
+
npm run lint
|
|
107
|
+
|
|
108
|
+
# Форматирование кода
|
|
109
|
+
npm run format
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Лицензия
|
|
113
|
+
|
|
114
|
+
MIT
|
|
115
|
+
|
|
116
|
+
## Автор
|
|
117
|
+
|
|
118
|
+
Danila Fokin <sir.sotoros@ys.ru>
|
|
119
|
+
|
|
120
|
+
## Ссылки
|
|
121
|
+
|
|
122
|
+
- [Документация Gotenberg](https://gotenberg.dev/)
|
|
123
|
+
- [Документация n8n](https://docs.n8n.io/)
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Gotenberg = void 0;
|
|
7
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
|
+
const n8n_workflow_2 = require("n8n-workflow");
|
|
9
|
+
const form_data_1 = __importDefault(require("form-data"));
|
|
10
|
+
class Gotenberg {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.description = {
|
|
13
|
+
displayName: 'Gotenberg',
|
|
14
|
+
name: 'gotenberg',
|
|
15
|
+
icon: 'file:gotenberg.svg',
|
|
16
|
+
group: ['transform'],
|
|
17
|
+
version: 1,
|
|
18
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
19
|
+
description: 'Convert documents to PDF using Gotenberg',
|
|
20
|
+
defaults: {
|
|
21
|
+
name: 'Gotenberg',
|
|
22
|
+
},
|
|
23
|
+
inputs: ['main'],
|
|
24
|
+
outputs: ['main'],
|
|
25
|
+
properties: [
|
|
26
|
+
{
|
|
27
|
+
displayName: 'Gotenberg URL',
|
|
28
|
+
name: 'gotenbergUrl',
|
|
29
|
+
type: 'string',
|
|
30
|
+
default: 'http://localhost:3000',
|
|
31
|
+
placeholder: 'http://localhost:3000',
|
|
32
|
+
description: 'Base URL of the Gotenberg server',
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
displayName: 'Operation',
|
|
37
|
+
name: 'operation',
|
|
38
|
+
type: 'options',
|
|
39
|
+
noDataExpression: true,
|
|
40
|
+
options: [
|
|
41
|
+
{
|
|
42
|
+
name: 'Convert HTML',
|
|
43
|
+
value: 'html',
|
|
44
|
+
action: 'Convert html to PDF',
|
|
45
|
+
description: 'Convert HTML to PDF',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'Convert Markdown',
|
|
49
|
+
value: 'markdown',
|
|
50
|
+
action: 'Convert markdown to PDF',
|
|
51
|
+
description: 'Convert Markdown to PDF',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'Convert Office Documents',
|
|
55
|
+
value: 'office',
|
|
56
|
+
action: 'Convert office documents to PDF',
|
|
57
|
+
description: 'Convert Office documents (Word, Excel, PowerPoint) to PDF',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'Convert URL',
|
|
61
|
+
value: 'url',
|
|
62
|
+
action: 'Convert url to PDF',
|
|
63
|
+
description: 'Convert URL to PDF',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'Merge PDFs',
|
|
67
|
+
value: 'merge',
|
|
68
|
+
action: 'Merge multiple PDF files into one',
|
|
69
|
+
description: 'Merge multiple PDF files into one',
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
default: 'office',
|
|
73
|
+
required: true,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
displayName: 'Binary Property',
|
|
77
|
+
name: 'binaryPropertyName',
|
|
78
|
+
type: 'string',
|
|
79
|
+
default: '',
|
|
80
|
+
description: 'Name of the binary property that contains the file(s) to convert. If empty, all binary properties from the previous node will be processed.',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
displayName: 'Output Binary Property',
|
|
84
|
+
name: 'outputBinaryPropertyName',
|
|
85
|
+
type: 'string',
|
|
86
|
+
default: 'data',
|
|
87
|
+
description: 'Name of the binary property to save the converted PDF',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
displayName: 'Options',
|
|
91
|
+
name: 'options',
|
|
92
|
+
type: 'collection',
|
|
93
|
+
placeholder: 'Add Option',
|
|
94
|
+
default: {},
|
|
95
|
+
options: [
|
|
96
|
+
{
|
|
97
|
+
displayName: 'Landscape',
|
|
98
|
+
name: 'landscape',
|
|
99
|
+
type: 'boolean',
|
|
100
|
+
default: false,
|
|
101
|
+
description: 'Whether to use landscape orientation',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
displayName: 'Page Ranges',
|
|
105
|
+
name: 'pageRanges',
|
|
106
|
+
type: 'string',
|
|
107
|
+
default: '',
|
|
108
|
+
description: 'Page ranges to include (e.g., "1-2,4-5")',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
displayName: 'Scale',
|
|
112
|
+
name: 'scale',
|
|
113
|
+
type: 'number',
|
|
114
|
+
typeOptions: {
|
|
115
|
+
minValue: 0.1,
|
|
116
|
+
maxValue: 2,
|
|
117
|
+
},
|
|
118
|
+
default: 1,
|
|
119
|
+
description: 'Scale factor for the PDF',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
displayName: 'Wait Timeout',
|
|
123
|
+
name: 'waitTimeout',
|
|
124
|
+
type: 'string',
|
|
125
|
+
default: '30s',
|
|
126
|
+
description: 'Maximum time to wait for conversion (e.g., "30s", "1m")',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
displayName: 'Wait Delay',
|
|
130
|
+
name: 'waitDelay',
|
|
131
|
+
type: 'string',
|
|
132
|
+
default: '0s',
|
|
133
|
+
description: 'Delay before starting conversion (e.g., "1s")',
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
async execute() {
|
|
141
|
+
const items = this.getInputData();
|
|
142
|
+
const returnData = [];
|
|
143
|
+
const gotenbergUrl = this.getNodeParameter('gotenbergUrl', 0);
|
|
144
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
145
|
+
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0) || '';
|
|
146
|
+
const outputBinaryPropertyName = this.getNodeParameter('outputBinaryPropertyName', 0);
|
|
147
|
+
const options = this.getNodeParameter('options', 0, {});
|
|
148
|
+
// Вспомогательная функция для получения расширения файла из MIME типа
|
|
149
|
+
const getFileExtensionFromMimeType = (mimeType) => {
|
|
150
|
+
const mimeToExt = {
|
|
151
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
|
152
|
+
'application/msword': 'doc',
|
|
153
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
|
154
|
+
'application/vnd.ms-excel': 'xls',
|
|
155
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
|
|
156
|
+
'application/vnd.ms-powerpoint': 'ppt',
|
|
157
|
+
'text/html': 'html',
|
|
158
|
+
'text/markdown': 'md',
|
|
159
|
+
'application/pdf': 'pdf',
|
|
160
|
+
};
|
|
161
|
+
return mimeToExt[mimeType] || 'bin';
|
|
162
|
+
};
|
|
163
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
164
|
+
try {
|
|
165
|
+
const item = items[itemIndex];
|
|
166
|
+
const binaryData = item.binary;
|
|
167
|
+
if (!binaryData || Object.keys(binaryData).length === 0) {
|
|
168
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No binary data found in item ${itemIndex}. Please make sure the binary property exists.`, { itemIndex });
|
|
169
|
+
}
|
|
170
|
+
// Создаем FormData для отправки в Gotenberg
|
|
171
|
+
const formData = new form_data_1.default();
|
|
172
|
+
let totalFilesCount = 0;
|
|
173
|
+
// Определяем, какие binary свойства обрабатывать
|
|
174
|
+
const binaryPropertiesToProcess = binaryPropertyName
|
|
175
|
+
? [binaryPropertyName]
|
|
176
|
+
: Object.keys(binaryData);
|
|
177
|
+
// Обрабатываем все указанные binary свойства
|
|
178
|
+
for (const propName of binaryPropertiesToProcess) {
|
|
179
|
+
const binaryProperty = binaryData[propName];
|
|
180
|
+
if (!binaryProperty) {
|
|
181
|
+
if (binaryPropertyName) {
|
|
182
|
+
// Если явно указано свойство, но его нет - ошибка
|
|
183
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Binary property "${propName}" not found in item ${itemIndex}`, { itemIndex });
|
|
184
|
+
}
|
|
185
|
+
// Если не указано явно - просто пропускаем отсутствующие свойства
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// Обрабатываем как одиночное значение, так и массив
|
|
189
|
+
const binaryItems = Array.isArray(binaryProperty) ? binaryProperty : [binaryProperty];
|
|
190
|
+
// Добавляем все файлы из этого свойства
|
|
191
|
+
for (let i = 0; i < binaryItems.length; i++) {
|
|
192
|
+
const binaryItem = binaryItems[i];
|
|
193
|
+
if (!binaryItem || !binaryItem.data) {
|
|
194
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Binary item ${i} in property "${propName}" is missing data`, { itemIndex });
|
|
195
|
+
}
|
|
196
|
+
// Получаем buffer из binary данных
|
|
197
|
+
// В n8n, когда binary данные приходят как массив, каждый элемент уже содержит data в base64
|
|
198
|
+
let dataBuffer;
|
|
199
|
+
if (Array.isArray(binaryProperty)) {
|
|
200
|
+
// Если это массив, декодируем base64 из элемента массива
|
|
201
|
+
dataBuffer = Buffer.from(binaryItem.data, 'base64');
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Если это одиночное значение, используем helper
|
|
205
|
+
dataBuffer = await this.helpers.getBinaryDataBuffer(itemIndex, propName);
|
|
206
|
+
}
|
|
207
|
+
const fileName = binaryItem.fileName ||
|
|
208
|
+
`${propName}_${i}.${getFileExtensionFromMimeType(binaryItem.mimeType || '')}`;
|
|
209
|
+
formData.append('files', dataBuffer, {
|
|
210
|
+
filename: fileName,
|
|
211
|
+
contentType: binaryItem.mimeType || 'application/octet-stream',
|
|
212
|
+
});
|
|
213
|
+
totalFilesCount++;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (totalFilesCount === 0) {
|
|
217
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No valid binary files found in item ${itemIndex}`, { itemIndex });
|
|
218
|
+
}
|
|
219
|
+
// Добавляем опции в зависимости от операции
|
|
220
|
+
if (operation === 'office' || operation === 'html' || operation === 'markdown') {
|
|
221
|
+
if (options.landscape) {
|
|
222
|
+
formData.append('landscape', 'true');
|
|
223
|
+
}
|
|
224
|
+
if (options.pageRanges) {
|
|
225
|
+
formData.append('pageRanges', options.pageRanges);
|
|
226
|
+
}
|
|
227
|
+
if (options.scale !== undefined) {
|
|
228
|
+
formData.append('scale', options.scale.toString());
|
|
229
|
+
}
|
|
230
|
+
if (options.waitTimeout) {
|
|
231
|
+
formData.append('waitTimeout', options.waitTimeout);
|
|
232
|
+
}
|
|
233
|
+
if (options.waitDelay) {
|
|
234
|
+
formData.append('waitDelay', options.waitDelay);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Определяем endpoint в зависимости от операции
|
|
238
|
+
let endpoint = '';
|
|
239
|
+
switch (operation) {
|
|
240
|
+
case 'office':
|
|
241
|
+
endpoint = '/convert/office';
|
|
242
|
+
break;
|
|
243
|
+
case 'html':
|
|
244
|
+
endpoint = '/convert/html';
|
|
245
|
+
break;
|
|
246
|
+
case 'markdown':
|
|
247
|
+
endpoint = '/convert/markdown';
|
|
248
|
+
break;
|
|
249
|
+
case 'url':
|
|
250
|
+
endpoint = '/convert/url';
|
|
251
|
+
// Для URL операции нужен параметр url
|
|
252
|
+
if (item.json.url) {
|
|
253
|
+
formData.append('url', item.json.url);
|
|
254
|
+
}
|
|
255
|
+
break;
|
|
256
|
+
case 'merge':
|
|
257
|
+
endpoint = '/forms/pdfengines/merge';
|
|
258
|
+
break;
|
|
259
|
+
default:
|
|
260
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`, { itemIndex });
|
|
261
|
+
}
|
|
262
|
+
// Отправляем запрос в Gotenberg
|
|
263
|
+
const url = `${gotenbergUrl.replace(/\/$/, '')}${endpoint}`;
|
|
264
|
+
const response = await this.helpers.httpRequest({
|
|
265
|
+
method: 'POST',
|
|
266
|
+
url,
|
|
267
|
+
body: formData,
|
|
268
|
+
returnFullResponse: true,
|
|
269
|
+
headers: formData.getHeaders(),
|
|
270
|
+
});
|
|
271
|
+
// Проверяем статус ответа
|
|
272
|
+
if (response.statusCode && response.statusCode >= 400) {
|
|
273
|
+
let errorText;
|
|
274
|
+
if (Buffer.isBuffer(response.body)) {
|
|
275
|
+
errorText = response.body.toString('utf-8');
|
|
276
|
+
}
|
|
277
|
+
else if (typeof response.body === 'string') {
|
|
278
|
+
errorText = response.body;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
errorText = JSON.stringify(response.body);
|
|
282
|
+
}
|
|
283
|
+
throw new n8n_workflow_2.NodeApiError(this.getNode(), {
|
|
284
|
+
message: `Gotenberg API error: ${response.statusCode}`,
|
|
285
|
+
description: errorText,
|
|
286
|
+
}, { itemIndex });
|
|
287
|
+
}
|
|
288
|
+
// Получаем PDF buffer
|
|
289
|
+
let pdfBuffer;
|
|
290
|
+
if (Buffer.isBuffer(response.body)) {
|
|
291
|
+
pdfBuffer = response.body;
|
|
292
|
+
}
|
|
293
|
+
else if (typeof response.body === 'string') {
|
|
294
|
+
pdfBuffer = Buffer.from(response.body, 'base64');
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
// Если это ArrayBuffer или другой тип
|
|
298
|
+
const bodyArray = new Uint8Array(response.body);
|
|
299
|
+
pdfBuffer = Buffer.from(bodyArray);
|
|
300
|
+
}
|
|
301
|
+
// Создаем выходной элемент
|
|
302
|
+
const newItem = {
|
|
303
|
+
json: {
|
|
304
|
+
...item.json,
|
|
305
|
+
success: true,
|
|
306
|
+
operation,
|
|
307
|
+
fileCount: totalFilesCount,
|
|
308
|
+
},
|
|
309
|
+
binary: {
|
|
310
|
+
...item.binary,
|
|
311
|
+
[outputBinaryPropertyName]: {
|
|
312
|
+
data: pdfBuffer.toString('base64'),
|
|
313
|
+
mimeType: 'application/pdf',
|
|
314
|
+
fileName: `converted_${itemIndex}.pdf`,
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
returnData.push(newItem);
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
if (this.continueOnFail()) {
|
|
322
|
+
returnData.push({
|
|
323
|
+
json: {
|
|
324
|
+
error: error instanceof Error ? error.message : String(error),
|
|
325
|
+
success: false,
|
|
326
|
+
},
|
|
327
|
+
binary: items[itemIndex].binary,
|
|
328
|
+
});
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
throw error;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return [returnData];
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
exports.Gotenberg = Gotenberg;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Gotenberg = void 0;
|
|
4
|
+
const Gotenberg_node_1 = require("./Gotenberg.node");
|
|
5
|
+
Object.defineProperty(exports, "Gotenberg", { enumerable: true, get: function () { return Gotenberg_node_1.Gotenberg; } });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
|
3
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
4
|
+
<line x1="16" y1="13" x2="8" y2="13"></line>
|
|
5
|
+
<line x1="16" y1="17" x2="8" y2="17"></line>
|
|
6
|
+
<polyline points="10 9 9 9 8 9"></polyline>
|
|
7
|
+
</svg>
|
|
8
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-sotoros-gotenberg",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n custom node for Gotenberg integration with binary data support",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node",
|
|
7
|
+
"gotenberg",
|
|
8
|
+
"pdf",
|
|
9
|
+
"converter"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "",
|
|
13
|
+
"author": "Danila Fokin <sir.sotoros@ys.ru> (https://github.com/sotoros)",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": ""
|
|
17
|
+
},
|
|
18
|
+
"main": "index.js",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc && gulp build:icons",
|
|
21
|
+
"dev": "tsc --watch",
|
|
22
|
+
"format": "prettier nodes --write",
|
|
23
|
+
"lint": "eslint nodes",
|
|
24
|
+
"lintfix": "eslint nodes --fix",
|
|
25
|
+
"prepublishOnly": "npm run build && npm run lint -s"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"n8n": {
|
|
31
|
+
"n8nNodesApiVersion": 1,
|
|
32
|
+
"nodes": [
|
|
33
|
+
"dist/nodes/Gotenberg/Gotenberg.node.js"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^18.15.0",
|
|
38
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
39
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
40
|
+
"eslint": "^8.57.0",
|
|
41
|
+
"eslint-plugin-n8n-nodes-base": "~1.11.0",
|
|
42
|
+
"gulp": "^4.0.2",
|
|
43
|
+
"n8n-workflow": "*",
|
|
44
|
+
"prettier": "^2.7.1",
|
|
45
|
+
"typescript": "^5.2.0"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"form-data": "^4.0.0",
|
|
49
|
+
"n8n-workflow": "*"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|