From a19ef26236a4386453bd3a69cf6e5cc4c01d63a8 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Mon, 21 Oct 2024 11:14:12 -0300 Subject: [PATCH] initial commit --- .dockerignore | 3 ++ .env.example | 1 + .gitignore | 3 ++ Dockerfile | 29 ++++++++++ LICENSE | 21 ++++++++ README.md | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 35 ++++++++++++ go.sum | 91 ++++++++++++++++++++++++++++++++ main.go | 140 ++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 466 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..db4baea --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +main + +.env diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..cee8df6 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +PORT=4040 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db4baea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +main + +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..12f06dd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,29 @@ +# Usar uma imagem base do Go +FROM golang:1.21-alpine + +# Instalar ffmpeg +RUN apk update && apk add --no-cache ffmpeg + +# Definir o diretório de trabalho no container +WORKDIR /app + +# Copiar os arquivos go.mod e go.sum para o diretório de trabalho +COPY go.mod go.sum ./ + +# Baixar as dependências +RUN go mod download + +# Copiar o código-fonte para o container +COPY . . + +# Compilar o binário do Go +RUN go build -o main . + +# Definir a variável de ambiente para a porta +ENV PORT=4040 + +# Expor a porta definida +EXPOSE ${PORT} + +# Comando para rodar o servidor +CMD ["./main"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cf57c93 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Evolution API + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..de9a2df --- /dev/null +++ b/README.md @@ -0,0 +1,143 @@ +# Evolution Audio Converter + +Este projeto é um micro serviço em Go que processa arquivos de áudio para whatsapp, os converte para o formato **opus** e retorna tanto a duração do áudio quanto o arquivo convertido em base64. O serviço aceita arquivos de áudio enviados como **form-data**, **base64** ou **URL**. + +## Requisitos + +Antes de começar, você precisará ter os seguintes itens instalados: + +- [Go](https://golang.org/doc/install) (versão 1.21 ou superior) +- [Docker](https://docs.docker.com/get-docker/) (para rodar o projeto em um container) +- [FFmpeg](https://ffmpeg.org/download.html) (para processamento de áudio) + +## Instalação + +### Clonar o Repositório + +Clone este repositório em sua máquina local: + +```bash +git clone https://github.com/EvolutionAPI/evolution-audio-converter.git +cd evolution-audio-converter +``` + +### Instalar Dependências + +Instale as dependências do projeto: + +```bash +go mod tidy +``` + +### Instalar o FFmpeg + +O serviço depende do **FFmpeg** para converter o áudio. Certifique-se de que o FFmpeg está instalado no seu sistema. + +- No Ubuntu: + + ```bash + sudo apt update + sudo apt install ffmpeg + ``` + +- No MacOS (via Homebrew): + + ```bash + brew install ffmpeg + ``` + +- No Windows, baixe o FFmpeg [aqui](https://ffmpeg.org/download.html) e adicione-o ao `PATH` do sistema. + +### Configuração + +Crie um arquivo `.env` no diretório raiz do projeto com a seguinte configuração: + +```env +PORT=4040 +``` + +Isso define a porta onde o serviço será executado. + +## Rodando o Projeto + +### Localmente + +Para rodar o serviço localmente, use o seguinte comando: + +```bash +go run main.go +``` + +O servidor estará disponível em `http://localhost:4040`. + +### Usando Docker + +Se preferir rodar o serviço em um container Docker, siga os passos abaixo: + +1. **Buildar a imagem Docker**: + + ```bash + docker build -t audio-service . + ``` + +2. **Rodar o container**: + + ```bash + docker run -p 4040:4040 --env-file=.env audio-service + ``` + + Isso irá iniciar o container na porta especificada no arquivo `.env`. + +## Como Usar + +Você pode enviar requisições `POST` para o endpoint `/process-audio` com um arquivo de áudio nos seguintes formatos: + +- **Form-data** (para enviar arquivos) +- **Base64** (para enviar o áudio codificado em base64) +- **URL** (para enviar o link do arquivo de áudio) + +### Exemplo de Requisição via cURL + +#### Envio como Form-data + +```bash +curl -X POST -F "file=@caminho/do/audio.mp3" http://localhost:4040/process-audio +``` + +#### Envio como Base64 + +```bash +curl -X POST -d "base64=$(base64 caminho/do/audio.mp3)" http://localhost:4040/process-audio +``` + +#### Envio como URL + +```bash +curl -X POST -d "url=https://exemplo.com/caminho/para/audio.mp3" http://localhost:4040/process-audio +``` + +### Resposta + +A resposta será um JSON contendo a duração do áudio e o arquivo convertido em base64: + +```json +{ + "duration": 120, + "audio": "UklGR... (base64 do arquivo)" +} +``` + +- `duration`: A duração do áudio em segundos. +- `audio`: O arquivo de áudio convertido para o formato opus, codificado em base64. + +## Licença + +Este projeto está sob a licença [MIT](LICENSE). +``` + +### Resumo do Conteúdo: +- **Requisitos**: Dependências necessárias (Go, Docker, FFmpeg). +- **Instalação**: Como clonar o repositório, instalar dependências e configurar o arquivo `.env`. +- **Rodando o projeto**: Instruções para rodar o projeto localmente ou via Docker. +- **Como usar**: Exemplos de como fazer requisições para o serviço com `form-data`, `base64` ou URL, e o formato de resposta. +- **Licença**: Incluir uma seção para a licença, se aplicável. \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4b1a01d --- /dev/null +++ b/go.mod @@ -0,0 +1,35 @@ +module github.com/EvolutionAPI/evolution-audio-converter + +go 1.21.1 + +require github.com/gin-gonic/gin v1.10.0 + +require ( + github.com/bytedance/sonic v1.11.6 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7087cb7 --- /dev/null +++ b/go.sum @@ -0,0 +1,91 @@ +github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= +github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/main.go b/main.go new file mode 100644 index 0000000..5c6a27b --- /dev/null +++ b/main.go @@ -0,0 +1,140 @@ +package main + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + + "github.com/gin-gonic/gin" + "github.com/joho/godotenv" +) + +func convertAudioToOpusWithDuration(inputData []byte) ([]byte, int, error) { + cmd := exec.Command("ffmpeg", "-i", "pipe:0", "-ac", "1", "-ar", "16000", "-c:a", "libopus", "-f", "ogg", "pipe:1") + + var outBuffer bytes.Buffer + var errBuffer bytes.Buffer + + cmd.Stdin = bytes.NewReader(inputData) + cmd.Stdout = &outBuffer + cmd.Stderr = &errBuffer + + err := cmd.Run() + if err != nil { + return nil, 0, fmt.Errorf("error during conversion: %v, details: %s", err, errBuffer.String()) + } + + convertedData := outBuffer.Bytes() + + outputText := errBuffer.String() + + splitTime := strings.Split(outputText, "time=") + + if len(splitTime) < 2 { + return nil, 0, errors.New("duração não encontrada") + } + + re := regexp.MustCompile(`(\d+):(\d+):(\d+\.\d+)`) + matches := re.FindStringSubmatch(string(splitTime[2])) + if len(matches) != 4 { + return nil, 0, errors.New("formato de duração não encontrado") + } + + hours, _ := strconv.ParseFloat(matches[1], 64) + minutes, _ := strconv.ParseFloat(matches[2], 64) + seconds, _ := strconv.ParseFloat(matches[3], 64) + duration := int(hours*3600 + minutes*60 + seconds) + + return convertedData, duration, nil +} + +func processAudio(c *gin.Context) { + var inputData []byte + var err error + + // Verifica se o arquivo foi enviado como form-data + file, _, err := c.Request.FormFile("file") + if err == nil { + inputData, err = ioutil.ReadAll(file) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Erro ao ler o arquivo"}) + return + } + } else { + // Verifica se foi enviado um base64 + base64Data := c.PostForm("base64") + if base64Data != "" { + inputData, err = base64.StdEncoding.DecodeString(base64Data) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Erro ao decodificar base64"}) + return + } + } else { + // Verifica se foi enviada uma URL + url := c.PostForm("url") + if url != "" { + resp, err := http.Get(url) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Erro ao obter o arquivo da URL"}) + return + } + defer resp.Body.Close() + inputData, err = io.ReadAll(resp.Body) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Erro ao ler o arquivo da URL"}) + return + } + } else { + c.JSON(http.StatusBadRequest, gin.H{"error": "Nenhum arquivo, base64 ou URL fornecido"}) + return + } + } + } + + // Chama a função para converter o áudio e obter a duração + convertedData, duration, err := convertAudioToOpusWithDuration(inputData) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + // Codifica o áudio convertido para base64 + base64Audio := base64.StdEncoding.EncodeToString(convertedData) + + // Retorna a resposta em JSON + c.JSON(http.StatusOK, gin.H{ + "duration": duration, + "audio": base64Audio, + }) +} + +func main() { + // Carrega o arquivo .env + err := godotenv.Load() + if err != nil { + fmt.Println("Erro ao carregar o arquivo .env") + } + + // Obtém a porta do arquivo .env ou usa a porta 8080 por padrão + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + + router := gin.Default() + + // Endpoint para processar o áudio + router.POST("/process-audio", processAudio) + + // Inicia o servidor na porta especificada + router.Run(":" + port) +}