328 lines
14 KiB
PHP
328 lines
14 KiB
PHP
<?php
|
|
header('Content-Type: application/json');
|
|
require_once __DIR__ . '/vendor/autoload.php';
|
|
require_once __DIR__ . '/db/config.php';
|
|
|
|
use Kunnu\Dropbox\Dropbox;
|
|
use Kunnu\Dropbox\DropboxApp;
|
|
use Kunnu\Dropbox\DropboxFile;
|
|
use Kunnu\Dropbox\Exceptions\DropboxClientException;
|
|
|
|
$response = [];
|
|
$action = $_GET['action'] ?? '';
|
|
|
|
switch ($action) {
|
|
case 'save':
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$url = $data['url'] ?? null;
|
|
$filename = $data['filename'] ?? null;
|
|
$token = $data['token'] ?? null;
|
|
|
|
if (empty($url) || empty($filename)) {
|
|
http_response_code(400);
|
|
$response['error'] = 'URL do stream e nome do arquivo são obrigatórios.';
|
|
} elseif (!filter_var($url, FILTER_VALIDATE_URL)) {
|
|
http_response_code(400);
|
|
$response['error'] = 'URL do stream inválida.';
|
|
} else {
|
|
try {
|
|
$pdo = db();
|
|
$stmt = $pdo->prepare(
|
|
"INSERT INTO streams (url, filename, dropbox_token, status) VALUES (:url, :filename, :token, 'pending')"
|
|
);
|
|
$stmt->execute([
|
|
':url' => $url,
|
|
':filename' => $filename,
|
|
':token' => $token
|
|
]);
|
|
$newId = $pdo->lastInsertId();
|
|
|
|
http_response_code(201);
|
|
$response['success'] = true;
|
|
$response['message'] = 'Stream salvo com sucesso! Pronto para conversão.';
|
|
$response['job_id'] = $newId;
|
|
} catch (PDOException $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro no banco de dados: ' . $e->getMessage();
|
|
}
|
|
}
|
|
} else {
|
|
http_response_code(405);
|
|
$response['error'] = 'Método não permitido para esta ação.';
|
|
}
|
|
break;
|
|
|
|
case 'get_streams':
|
|
try {
|
|
$pdo = db();
|
|
$stmt = $pdo->query("SELECT id, url, filename, status, created_at, progress FROM streams ORDER BY created_at DESC");
|
|
$streams = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
$response['success'] = true;
|
|
$response['streams'] = $streams;
|
|
} catch (PDOException $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro no banco de dados: ' . $e->getMessage();
|
|
}
|
|
break;
|
|
|
|
case 'convert_to_mp4':
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$id = $data['id'] ?? null;
|
|
|
|
if (empty($id)) {
|
|
http_response_code(400);
|
|
$response['error'] = 'O ID do stream é obrigatório.';
|
|
} else {
|
|
try {
|
|
$pdo = db();
|
|
$stmt = $pdo->prepare("SELECT url, filename FROM streams WHERE id = :id");
|
|
$stmt->execute([':id' => $id]);
|
|
$stream = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$stream) {
|
|
http_response_code(404);
|
|
$response['error'] = 'Stream não encontrado.';
|
|
} else {
|
|
$ffprobe_command = [
|
|
'ffprobe',
|
|
'-v', 'error',
|
|
'-show_entries', 'format=duration',
|
|
'-of', 'default=noprint_wrappers=1:nokey=1',
|
|
$stream['url']
|
|
];
|
|
$duration_process = new \Symfony\Component\Process\Process($ffprobe_command);
|
|
$duration_process->run();
|
|
$duration = (float)$duration_process->getOutput();
|
|
|
|
$output_filename = pathinfo($stream['filename'], PATHINFO_FILENAME) . '_' . time() . '.mp4';
|
|
$output_path = __DIR__ . '/videos/' . $output_filename;
|
|
|
|
$pdo->prepare("UPDATE streams SET status = 'converting', duration = :duration, output_filename = :output_filename WHERE id = :id")->execute([
|
|
':duration' => $duration,
|
|
':output_filename' => $output_filename,
|
|
':id' => $id
|
|
]);
|
|
$progress_log_path = sys_get_temp_dir() . '/' . $output_filename . '.log';
|
|
|
|
if (!is_dir(__DIR__ . '/videos')) {
|
|
mkdir(__DIR__ . '/videos', 0775, true);
|
|
}
|
|
|
|
$command = [
|
|
'ffmpeg',
|
|
'-y',
|
|
'-v', 'quiet',
|
|
'-progress', $progress_log_path,
|
|
'-i', $stream['url'],
|
|
'-c:v', 'libx264',
|
|
'-preset', 'veryfast',
|
|
'-crf', '23',
|
|
'-c:a', 'aac',
|
|
'-b:a', '128k',
|
|
$output_path
|
|
];
|
|
|
|
$process = new \Symfony\Component\Process\Process($command);
|
|
$process->setTimeout(3600);
|
|
$process->start();
|
|
|
|
$response['success'] = true;
|
|
$response['message'] = 'A conversão do vídeo foi iniciada.';
|
|
}
|
|
} catch (PDOException $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro no banco de dados: ' . $e->getMessage();
|
|
} catch (\Exception $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro na conversão: ' . $e->getMessage();
|
|
}
|
|
}
|
|
} else {
|
|
http_response_code(405);
|
|
$response['error'] = 'Método não permitido para esta ação.';
|
|
}
|
|
break;
|
|
|
|
case 'get_conversion_progress':
|
|
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
|
$id = $_GET['id'] ?? null;
|
|
|
|
if (empty($id)) {
|
|
http_response_code(400);
|
|
$response['error'] = 'O ID do stream é obrigatório.';
|
|
} else {
|
|
try {
|
|
$pdo = db();
|
|
$stmt = $pdo->prepare("SELECT duration, converted_path, output_filename FROM streams WHERE id = :id");
|
|
$stmt->execute([':id' => $id]);
|
|
$stream = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$stream) {
|
|
http_response_code(404);
|
|
$response['error'] = 'Stream não encontrado.';
|
|
} else {
|
|
$output_filename = $stream['output_filename'];
|
|
if(empty($output_filename)) {
|
|
$response['progress'] = 0;
|
|
$response['success'] = true;
|
|
} else {
|
|
$progress_log_path = sys_get_temp_dir() . '/' . $output_filename . '.log';
|
|
|
|
if (!file_exists($progress_log_path)) {
|
|
$response['progress'] = 0;
|
|
} else {
|
|
$log_content = file_get_contents($progress_log_path);
|
|
preg_match_all("/out_time_ms=(\d+)/", $log_content, $matches);
|
|
$last_match = end($matches[1]);
|
|
|
|
if ($last_match) {
|
|
$processed_ms = (float)$last_match / 1000000;
|
|
$duration = (float)$stream['duration'];
|
|
$progress = $duration > 0 ? round(($processed_ms / $duration) * 100) : 0;
|
|
$progress = min(100, $progress);
|
|
|
|
$pdo->prepare("UPDATE streams SET progress = :progress WHERE id = :id")->execute([':progress' => $progress, ':id' => $id]);
|
|
|
|
if ($progress == 100) {
|
|
$pdo->prepare("UPDATE streams SET status = 'completed', converted_path = :converted_path WHERE id = :id")->execute([':converted_path' => $output_filename, ':id' => $id]);
|
|
if (file_exists($progress_log_path)) unlink($progress_log_path);
|
|
}
|
|
|
|
$response['progress'] = $progress;
|
|
} else {
|
|
$response['progress'] = 0;
|
|
}
|
|
}
|
|
$response['success'] = true;
|
|
}
|
|
|
|
}
|
|
} catch (PDOException $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro no banco de dados: ' . $e->getMessage();
|
|
} catch (\Exception $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro ao obter progresso: ' . $e->getMessage();
|
|
}
|
|
}
|
|
} else {
|
|
http_response_code(405);
|
|
$response['error'] = 'Método não permitido para esta ação.';
|
|
}
|
|
break;
|
|
|
|
case 'send_to_dropbox':
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$id = $data['id'] ?? null;
|
|
$token = $data['token'] ?? null;
|
|
|
|
if (empty($id) || empty($token)) {
|
|
http_response_code(400);
|
|
$response['error'] = 'O ID do stream e o token do Dropbox são obrigatórios.';
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$pdo = db();
|
|
$stmt = $pdo->prepare("SELECT converted_path FROM streams WHERE id = :id AND status = 'completed'");
|
|
$stmt->execute([':id' => $id]);
|
|
$stream = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$stream || empty($stream['converted_path'])) {
|
|
http_response_code(404);
|
|
$response['error'] = 'Arquivo convertido não encontrado ou o stream não está completo.';
|
|
break;
|
|
}
|
|
|
|
$filePath = __DIR__ . '/videos/' . $stream['converted_path'];
|
|
if (!file_exists($filePath)) {
|
|
http_response_code(404);
|
|
$response['error'] = 'Arquivo físico não encontrado no servidor.';
|
|
break;
|
|
}
|
|
|
|
$app = new DropboxApp("", "", $token);
|
|
$dropbox = new Dropbox($app);
|
|
|
|
$dropboxFileName = '/' . basename($filePath);
|
|
$dropboxFile = new DropboxFile($filePath);
|
|
$file = $dropbox->upload($dropboxFile, $dropboxFileName, ['autorename' => true]);
|
|
|
|
$response['success'] = true;
|
|
$response['message'] = 'Arquivo enviado com sucesso para o Dropbox!';
|
|
$response['file_name'] = $file->getName();
|
|
|
|
} catch (PDOException $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro no banco de dados: ' . $e->getMessage();
|
|
} catch (DropboxClientException $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro no Dropbox: ' . $e->getMessage();
|
|
} catch (Exception $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Ocorreu um erro inesperado: ' . $e->getMessage();
|
|
}
|
|
} else {
|
|
http_response_code(405);
|
|
$response['error'] = 'Método não permitido para esta ação.';
|
|
}
|
|
break;
|
|
|
|
case 'delete':
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$data = json_decode(file_get_contents('php://input'), true);
|
|
$id = $data['id'] ?? null;
|
|
|
|
if (empty($id)) {
|
|
http_response_code(400);
|
|
$response['error'] = 'O ID do stream é obrigatório.';
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$pdo = db();
|
|
$stmt = $pdo->prepare("SELECT converted_path FROM streams WHERE id = :id");
|
|
$stmt->execute([':id' => $id]);
|
|
$stream = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($stream && !empty($stream['converted_path'])) {
|
|
$filePath = __DIR__ . '/videos/' . $stream['converted_path'];
|
|
if (file_exists($filePath)) {
|
|
unlink($filePath);
|
|
}
|
|
}
|
|
|
|
$stmt = $pdo->prepare("DELETE FROM streams WHERE id = :id");
|
|
$stmt->execute([':id' => $id]);
|
|
|
|
if ($stmt->rowCount() > 0) {
|
|
$response['success'] = true;
|
|
$response['message'] = 'Vídeo e registro apagados com sucesso!';
|
|
} else {
|
|
http_response_code(404);
|
|
$response['error'] = 'Nenhum vídeo encontrado com este ID.';
|
|
}
|
|
|
|
} catch (PDOException $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Erro no banco de dados: ' . $e->getMessage();
|
|
} catch (\Exception $e) {
|
|
http_response_code(500);
|
|
$response['error'] = 'Ocorreu um erro inesperado: ' . $e->getMessage();
|
|
}
|
|
} else {
|
|
http_response_code(405);
|
|
$response['error'] = 'Método não permitido para esta ação.';
|
|
}
|
|
break;
|
|
|
|
default:
|
|
http_response_code(400);
|
|
$response['error'] = 'Ação não especificada ou inválida.';
|
|
break;
|
|
}
|
|
|
|
echo json_encode($response); |