opex792 commited on
Commit
b5bcffb
·
verified ·
1 Parent(s): 3aa3b77

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +39 -55
index.js CHANGED
@@ -1,8 +1,8 @@
1
  import express from 'express';
2
  import multer from 'multer';
3
  import { spawn } from 'child_process';
4
- import { writeFile, unlink } from 'fs/promises';
5
- import { createReadStream, watch } from 'fs';
6
  import path from 'path';
7
  import { v4 as uuidv4 } from 'uuid';
8
  import fetch from 'node-fetch';
@@ -29,7 +29,7 @@ const downloadFile = async (url) => {
29
  return Buffer.from(arrayBuffer);
30
  };
31
 
32
- // --- "УМНЫЙ" ЭНДПОИНТ С НАСТОЯЩИМ LIVE-СТРИМИНГОМ ДЛЯ FFMPEG ---
33
  app.post('/api/run/stream', upload.single('file'), async (req, res) => {
34
  try {
35
  const { command, args: argsJson, file_url } = req.body;
@@ -53,61 +53,45 @@ app.post('/api/run/stream', upload.single('file'), async (req, res) => {
53
  return res.status(400).json({ error: 'A file must be provided via "file" or "file_url".' });
54
  }
55
 
56
- // --- СПЕЦИАЛЬНАЯ ЛОГИКА ДЛЯ FFMPEG (LIVE STREAMING) ---
57
  if (command === 'ffmpeg') {
58
  const inputFilePath = path.join(TEMP_DIR, `${uuidv4()}-input`);
59
  const outputFilePath = path.join(TEMP_DIR, `${uuidv4()}-output`);
60
 
61
- await writeFile(inputFilePath, inputBuffer);
62
-
63
- const processedArgs = args.map(arg =>
64
- arg.replace('{INPUT_FILE}', inputFilePath)
65
- .replace('{OUTPUT_FILE}', outputFilePath)
66
- );
67
-
68
- const ffmpegProcess = spawn(command, processedArgs);
69
-
70
- // Функция для очистки
71
- const cleanup = () => {
72
- ffmpegProcess.kill('SIGKILL'); // Убеждаемся, что процесс завершен
73
- unlink(inputFilePath).catch(() => {});
74
- unlink(outputFilePath).catch(() => {});
75
- };
76
-
77
- // Как только ffmpeg создаст выходной файл, начинаем его стримить
78
- const watcher = watch(TEMP_DIR, (eventType, filename) => {
79
- if (filename === path.basename(outputFilePath)) {
80
- res.setHeader('Content-Type', 'application/octet-stream');
81
- const outputStream = createReadStream(outputFilePath);
82
- outputStream.pipe(res);
83
- // Прекращаем следить за файлом после того, как он найден
84
- watcher.close();
85
- }
86
- });
87
-
88
- // Если пользователь закроет соединение, убиваем ffmpeg и чистим файлы
89
- res.on('close', () => {
90
- cleanup();
91
- });
92
-
93
- ffmpegProcess.on('close', (code) => {
94
- watcher.close(); // На всякий случай
95
- // Если ffmpeg завершился с ошибкой до того, как мы начали стримить
96
- if (!res.headersSent) {
97
- res.status(500).json({ error: 'ffmpeg failed before output was generated.', code: code });
98
- }
99
- // Файлы будут удалены после завершения стрима (если он начался) или сразу
100
- setTimeout(cleanup, 100); // Небольшая задержка для завершения потока
101
- });
102
-
103
- ffmpegProcess.on('error', (err) => {
104
- watcher.close();
105
- if (!res.headersSent) {
106
- res.status(500).json({ error: 'Failed to start ffmpeg.', message: err.message });
107
- }
108
- cleanup();
109
- });
110
-
111
  // --- ОБЫЧНАЯ ЛОГИКА ДЛЯ ДРУГИХ КОМАНД ---
112
  } else {
113
  const process = spawn(command, args);
@@ -137,6 +121,7 @@ app.post('/api/run/stream', upload.single('file'), async (req, res) => {
137
  });
138
 
139
 
 
140
  // ... (остальной код для /api/task/* и /api/download/* без изменений) ...
141
 
142
  const executeTask = async (taskId) => {
@@ -252,4 +237,3 @@ app.get('/api/download/:fileId', (req, res) => {
252
 
253
  app.listen(PORT, () => { startCleanupJob(); });
254
 
255
-
 
1
  import express from 'express';
2
  import multer from 'multer';
3
  import { spawn } from 'child_process';
4
+ import { writeFile, unlink, readFile } from 'fs/promises';
5
+ import { createReadStream } from 'fs';
6
  import path from 'path';
7
  import { v4 as uuidv4 } from 'uuid';
8
  import fetch from 'node-fetch';
 
29
  return Buffer.from(arrayBuffer);
30
  };
31
 
32
+ // --- "УМНЫЙ" ЭНДПОИНТ ДЛЯ ПОТОКОВОЙ ОБРАБОТКИ ---
33
  app.post('/api/run/stream', upload.single('file'), async (req, res) => {
34
  try {
35
  const { command, args: argsJson, file_url } = req.body;
 
53
  return res.status(400).json({ error: 'A file must be provided via "file" or "file_url".' });
54
  }
55
 
56
+ // --- СПЕЦИАЛЬНАЯ ЛОГИКА ДЛЯ FFMPEG ---
57
  if (command === 'ffmpeg') {
58
  const inputFilePath = path.join(TEMP_DIR, `${uuidv4()}-input`);
59
  const outputFilePath = path.join(TEMP_DIR, `${uuidv4()}-output`);
60
 
61
+ try {
62
+ await writeFile(inputFilePath, inputBuffer);
63
+
64
+ const processedArgs = args.map(arg =>
65
+ arg.replace('{INPUT_FILE}', inputFilePath)
66
+ .replace('{OUTPUT_FILE}', outputFilePath)
67
+ );
68
+
69
+ const process = spawn(command, processedArgs);
70
+ let stderrChunks = [];
71
+ process.stderr.on('data', (data) => stderrChunks.push(data));
72
+
73
+ process.on('close', async (code) => {
74
+ if (code === 0) {
75
+ try {
76
+ const outputBuffer = await readFile(outputFilePath);
77
+ res.setHeader('Content-Type', 'application/octet-stream');
78
+ res.send(outputBuffer);
79
+ } catch (readError) {
80
+ res.status(500).json({ error: "Command succeeded, but failed to read output file.", message: readError.message });
81
+ }
82
+ } else {
83
+ const stderr = Buffer.concat(stderrChunks).toString('utf8');
84
+ res.status(500).json({ error: 'Command execution failed.', code: code, stderr: stderr });
85
+ }
86
+ // Очистка
87
+ await unlink(inputFilePath).catch(()=>{});
88
+ await unlink(outputFilePath).catch(()=>{});
89
+ });
90
+ } catch (execError) {
91
+ res.status(500).json({ error: "Failed during ffmpeg file operations.", message: execError.message });
92
+ await unlink(inputFilePath).catch(()=>{});
93
+ await unlink(outputFilePath).catch(()=>{});
94
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  // --- ОБЫЧНАЯ ЛОГИКА ДЛЯ ДРУГИХ КОМАНД ---
96
  } else {
97
  const process = spawn(command, args);
 
121
  });
122
 
123
 
124
+ // --- СИСТЕМА АСИНХРОННЫХ ЗАДАЧ (ОСТАЕТСЯ КАК АЛЬТЕРНАТИВА) ---
125
  // ... (остальной код для /api/task/* и /api/download/* без изменений) ...
126
 
127
  const executeTask = async (taskId) => {
 
237
 
238
  app.listen(PORT, () => { startCleanupJob(); });
239