# Coda Transcoder para Lidarr, escrito em Go e distribuído via Docker. Converte álbuns de **FLAC** para **MP3 320 kbps CBR**, acionado automaticamente por webhooks do Lidarr ou manualmente pela interface web. Em ambos os fluxos, o Coda converte os arquivos, valida o resultado, remove os FLACs originais e solicita ao Lidarr um rescan da biblioteca. ## Funcionalidades - Conversão FLAC → MP3 320 kbps CBR (libmp3lame), preservando metadados e capa. - Acionamento por **webhook** do Lidarr ou **manual** pela interface web. - Fila interna com worker pool e conversão paralela configurável. - Validação pós-conversão (ffprobe, tamanho, existência) antes de apagar qualquer FLAC. - **Janela de trabalho** opcional (desabilitada por padrão) para restringir o processamento a um intervalo de horário. - Interface web: dashboard, tarefas, logs, navegação/scan de FLACs e configurações. - Persistência em **SQLite** (jobs, logs e configurações). - Modo **dry run** para simular sem converter nem apagar. - Notificações via **ntfy** (self-hosted ou público) ao final de cada job. ## Stack | Camada | Escolha | |--------------|------------------------------------| | Linguagem | Go 1.25.x | | HTTP Router | chi (go-chi/chi/v5) | | Banco | SQLite (modernc.org/sqlite, sem CGO) | | UI | html/template + htmx + Tailwind CSS v4 + DaisyUI | | Logging | log/slog (stdlib) + handler SQLite | | Áudio | ffmpeg + ffprobe (libmp3lame) | | Distribuição | Docker (Alpine Linux) | ## Início Rápido (local, sem Docker) Pré-requisitos: **Go 1.25+** e **ffmpeg** com `libmp3lame`. No Fedora, o ffmpeg completo vem do RPM Fusion: ```bash sudo dnf install -y https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm sudo dnf install -y ffmpeg ``` Setup e execução: ```bash make setup # baixa Tailwind + DaisyUI + htmx, deps Go, cria .env mkdir -p data testdata/music # pastas locais (ajuste MUSIC_PATH no .env) make run # dev com hot-reload (http://localhost:8080) ``` O SQLite **não** precisa ser instalado (`modernc.org/sqlite` é Go puro). ## Comandos (Makefile) ```bash make setup # baixa ferramentas + deps + cria .env make css # gera web/static/app.css make css-watch # regenera o CSS ao salvar (dev) make run # dev (build tag dev, assets do disco, hot-reload) make run-prod # produção (assets embutidos via //go:embed) make build # binário de produção em bin/server make test # go test ./... make lint # go vet ./... make clean # remove bin/ e app.css ``` ## Docker ```bash docker build -t coda . docker run -d \ -p 8080:8080 \ -v /caminho/para/musica:/music \ -v coda-data:/data \ -e LIDARR_URL=http://lidarr:8686 \ -e LIDARR_API_KEY=... \ coda ``` Volumes: - **`/music`** — arquivos de música (mesmo path usado pelo Lidarr). - **`/data`** — volume persistente do SQLite (`coda.db`). ## Configuração Definida por variáveis de ambiente (defaults) e sobrescrita pela interface web (persistida no SQLite; a web vence). Em dev, o `.env` é carregado no startup. | Variável | Default | Descrição | |-----------------------|--------------------|----------------------------------------| | `PORT` | `8080` | Porta do servidor HTTP | | `WORKERS` | `4` | Workers simultâneos | | `FFMPEG_BIN` | `/usr/bin/ffmpeg` | Caminho do ffmpeg | | `FFPROBE_BIN` | `/usr/bin/ffprobe` | Caminho do ffprobe | | `LOG_LEVEL` | `INFO` | Nível de log | | `DRY_RUN` | `false` | Não converte nem apaga (só registra) | | `LIDARR_URL` | — | URL base do Lidarr | | `LIDARR_API_KEY` | — | API key do Lidarr | | `WEBHOOK_SECRET` | — | Segredo para validar webhooks | | `MUSIC_PATH` | `/music` | Diretório com os arquivos de música | | `DB_PATH` | `/data/coda.db` | Caminho do arquivo SQLite | | `TIMEZONE` | `UTC` | Timezone da janela de trabalho | | `WORK_WINDOW_ENABLED` | `false` | Habilita a janela de trabalho | | `WORK_WINDOW_START` | `08:00` | Início da janela (HH:MM) | | `WORK_WINDOW_END` | `18:00` | Fim da janela (HH:MM) | | `NTFY_ENABLED` | `false` | Habilita notificações ntfy | | `NTFY_URL` | — | URL base do servidor ntfy | | `NTFY_TOPIC` | — | Tópico para publicar notificações | | `NTFY_TOKEN` | — | Token de autenticação (opcional) | ## Integração com o Lidarr O Coda funciona como um pós-processador do Lidarr. Após o Lidarr importar um álbum, ele dispara um webhook para o Coda, que converte os FLACs para MP3 e solicita um rescan da biblioteca. ### Pré-requisito: paths compartilhados O Lidarr e o Coda precisam enxergar a biblioteca no **mesmo caminho absoluto**. Se o Lidarr acessa os arquivos em `/music`, o Coda também deve ter `/music` montado apontando para o mesmo diretório físico. ### 1. Configurar o Coda Defina as variáveis de ambiente (ou configure via `/settings` na interface web): | Variável | Descrição | |------------------|--------------------------------------------------------| | `LIDARR_URL` | URL base do Lidarr, ex: `http://lidarr:8686` | | `LIDARR_API_KEY` | API key do Lidarr (**Settings → General → API Key**) | | `WEBHOOK_SECRET` | Segredo para validar webhooks (opcional, mas recomendado) | | `MUSIC_PATH` | Caminho raiz da biblioteca, deve coincidir com o Lidarr | ### 2. Configurar o Webhook no Lidarr No Lidarr, acesse **Settings → Connect → + → Webhook** e configure: | Campo | Valor | |------------------------|----------------------------------------------| | **Name** | Coda (ou qualquer nome) | | **Notification Triggers** | `On Release Import` | | **URL** | `http://:8080/webhook` | | **Method** | POST | Se `WEBHOOK_SECRET` estiver definido, adicione um header: | Header | Valor | |---------------------|------------------| | `X-Webhook-Secret` | `` | Salve e clique em **Test** para validar. O Coda responderá com `{"status":"ok"}`. ### Fluxo completo ``` Lidarr importa álbum FLAC → POST /webhook (Lidarr → Coda) → Coda enfileira job → Worker converte FLAC → MP3, valida, remove FLACs → Coda chama API do Lidarr para rescan da pasta → Lidarr detecta os MP3s e atualiza a biblioteca ``` ## Estrutura do Projeto ``` cmd/server/ # entrypoint internal/ # config, scheduler, webhook, queue, worker, # transcoder, validator, lidarr, logger, web, # models, store, scanner, ntfy web/ # styles/ (fonte CSS), static/ (gerado), templates/ data/ # volume local do SQLite ``` ## Documentação - [Requisitos](docs/requirements.md) - [Arquitetura](docs/architecture.md) - [AGENTS.md](AGENTS.md) — guia para agentes e convenções do projeto