Servidor de streaming doméstico automatizado rodando em uma Orange Pi 5 (Rockchip RK3588S). Você pede um filme pelo celular, e alguns minutos depois ele aparece na sua "Netflix particular" já renomeado, catalogado e legendado em português. Tudo self-hosted, sem nenhum serviço externo pago.
A stack pronta está em assets/stacks/midia.yml.
Pré-requisito: Docker e Portainer instalados. Ver
./portainer-debian.md.
Important
Antes de subir esta stack, leia ./orangepi5-backup-restore.md.
A configuração dos *arrs acumulada ao longo de meses (indexadores, perfis, formatos
personalizados, histórico) vale mais que os arquivos de mídia, e ela só existe em /srv.
| Serviço | Papel |
|---|---|
| qBittorrent | Cliente de torrent. Recebe os magnet links e baixa |
| Prowlarr | Agregador de indexadores. Alimenta Radarr e Sonarr com as fontes de torrent |
| FlareSolverr | Proxy que resolve desafios Cloudflare de indexadores protegidos |
| Radarr | Gerencia filmes: procura, baixa, renomeia, organiza e faz upgrade de qualidade |
| Sonarr | O mesmo para séries e animes, com agenda de episódios que ainda vão ao ar |
| Bazarr | Busca e sincroniza legendas para o que Radarr e Sonarr importaram |
| Seerr | Portal de requisições. Fork do Overseerr. É por aqui que a família pede conteúdo |
| Plex | Player principal. Interface polida, apps em toda TV, console e celular |
| Jellyfin | Player alternativo, 100% aberto e o único com transcode por hardware nesta placa |
| Tautulli | Estatísticas e monitoramento de quem assistiu o quê no Plex |
| Yamtrack | Histórico de exibição self-hosted. Recebe por webhook o que você assiste |
| FileBot | Renomeador manual (interface gráfica via navegador) para o que os *arrs não pegaram |
┌──────────────┐
Você / família ─────►│ Seerr │ "quero assistir X"
└──────┬───────┘
│
┌─────────────┴─────────────┐
▼ ▼
┌────────────┐ ┌────────────┐
│ Radarr │ │ Sonarr │
│ (filmes) │ │ (séries) │
└─────┬──────┘ └──────┬─────┘
│ │
└────────────┬───────────────┘
▼
┌───────────────┐ ┌───────────────┐
│ Prowlarr │◄────►│ FlareSolverr │
│ (indexadores) │ │ (anti-CF) │
└───────┬───────┘ └───────────────┘
│ magnet link
▼
┌───────────────┐
│ qBittorrent │
└───────┬───────┘
│ baixa em /data/Downloads/torrents/
▼
╔═══════════════════════════╗
║ /srv/midia (HD 1 TB) ║
║ hardlink, sem duplicar ║
╚═══════╤═══════════╤═══════╝
│ │
┌──────────┘ └──────────┐
▼ ▼
┌────────────┐ ┌────────────┐
│ Bazarr │ legendas │ Plex/Jelly │──► TV, celular, PC
└────────────┘ └──────┬─────┘
│ webhook ao assistir
┌────────────┴────────────┐
▼ ▼
┌────────────┐ ┌───────────────┐
│ Tautulli │ │ Yamtrack │
│ (só Plex) │ │ (histórico) │
└────────────┘ └───────┬───────┘
│
┌───────▼───────┐
│ yamtrack-redis│
└───────────────┘
| Porta | Serviço | Observação |
|---|---|---|
8080/tcp |
qBittorrent | Web UI |
62609/tcp+udp |
qBittorrent | Porta de escuta do BitTorrent. Precisa ser aberta no roteador |
9696/tcp |
Prowlarr | Web UI |
8191/tcp |
FlareSolverr | API interna. Não expor à internet |
7878/tcp |
Radarr | Web UI |
8989/tcp |
Sonarr | Web UI |
6767/tcp |
Bazarr | Web UI |
5055/tcp |
Seerr | Web UI |
32400/tcp |
Plex | network_mode: host |
8096/tcp |
Jellyfin | network_mode: host |
8181/tcp |
Tautulli | Web UI |
8010/tcp |
Yamtrack | Web UI. Mapeia para a 8000 do container, porque a 8000 do host é do Portainer |
5800/tcp |
FileBot | Interface gráfica via navegador (noVNC) |
Este é o ponto que separa uma stack que funciona de uma que enche o disco pela metade. Todos os containers montam o mesmo caminho:
- /srv/midia:/dataQuando o Radarr importa um filme baixado, ele cria um hardlink: um segundo nome apontando para
os mesmos blocos no disco. O arquivo aparece em Filmes/ e continua em Downloads/ para semear,
ocupando o espaço uma vez só. A operação é instantânea, mesmo num arquivo de 40 GB.
Warning
Hardlink só funciona dentro do mesmo sistema de arquivos. Se você montar
/srv/midia/Downloads:/downloads e /srv/midia/Filmes:/movies como volumes separados, o Docker
apresenta os dois como dispositivos diferentes dentro do container, o hardlink falha e o Radarr
cai para cópia. Cada filme passa a ocupar o dobro.
É exatamente por isso que esta stack diverge do tutorial do AkitaOnRails, que separa /tv e
/downloads. Aqui seguimos o padrão do TRaSH Guides.
Para conferir se está funcionando, procure arquivos com mais de um link:
find /srv/midia -type f -links +1 | headSe a saída listar arquivos, os hardlinks estão ativos.
# Biblioteca (no HD grande)
sudo mkdir -p /srv/midia/{Filmes,Series,Animes}
sudo mkdir -p /srv/midia/Downloads/torrents/{radarr,tv-sonarr}
# Configurações dos containers (no disco do sistema)
sudo mkdir -p /srv/qbittorrent/config
sudo mkdir -p /srv/prowlarr/config
sudo mkdir -p /srv/radarr/appdata/config
sudo mkdir -p /srv/sonarr/appdata/config
sudo mkdir -p /srv/bazarr/appdata/config
sudo mkdir -p /srv/overseerr/config
sudo mkdir -p /srv/plex/{config,transcode}
sudo mkdir -p /srv/jellyfin/{config,cache}
sudo mkdir -p /srv/tautulli/config
sudo mkdir -p /srv/yamtrack/{db,redis}
sudo mkdir -p /srv/filebot/configNote
O Jellyfin usa tmpfs para os arquivos temporários de transcode, então não existe pasta
criada para eles. A pasta /srv/jellyfin/cache continua servindo para imagens e metadados.
Os containers rodam como UID/GID 1000. Se as pastas ficarem como root, os serviços sobem e
falham com EACCES na primeira escrita.
sudo chown -R 1000:1000 /srv/midia
sudo chown -R 1000:1000 /srv/{qbittorrent,prowlarr,radarr,sonarr,bazarr,overseerr}
sudo chown -R 1000:1000 /srv/{plex,jellyfin,tautulli,yamtrack,filebot}O
yamtrack-redisroda comuser: "1000:1000"na stack justamente para caber nesse mesmochown. A imagem oficial do Redis usaria o UID999e exigiria um comando à parte.
getent group video renderSaída esperada em uma Orange Pi 5:
video:x:44:orangepi
render:x:105:orangepi
Se os números forem diferentes na sua placa, ajuste o group_add do serviço jellyfin no YAML.
Esta é a pegadinha menos óbvia da stack, e ela atinge apenas os serviços em network_mode: host.
Containers que publicam portas com ports: são alcançáveis mesmo com o firewall fechado, porque o
Docker escreve as próprias regras na chain DOCKER do iptables e contorna o UFW. Já Plex e
Jellyfin usam a rede do host, então o tráfego bate na chain INPUT e obedece ao firewall.
O resultado confunde: Radarr e Sonarr abrem normalmente, e o Jellyfin não abre, mesmo com o
container saudável e respondendo em localhost dentro do servidor.
# O firewall está ativo e com política DROP?
sudo ufw status
# Liberar o Jellyfin
sudo ufw allow 8096/tcp comment 'Jellyfin'
# Opcional: descoberta automática pelos apps de TV e celular na LAN
sudo ufw allow 7359/udp comment 'Jellyfin discovery'
sudo ufw allow 1900/udp comment 'DLNA'
# O Plex costuma já estar liberado, confirme
sudo ufw status | grep 32400Como diagnosticar quando algo em network_mode: host não abre:
# Dentro do servidor: o serviço está escutando e respondendo?
sudo ss -tlnp | grep 8096
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8096/Se aqui responder (o Jellyfin devolve 302, que é o redirect para /web/) e mesmo assim não abrir
de outra máquina, o problema é firewall, não o container.
ls -l /dev/mpp_service /dev/rga /dev/mali0 && ls /dev/dri /dev/dma_heapTodos devem existir. Se /dev/mpp_service faltar, o kernel não está com os drivers de VPU do
Rockchip e o transcode por hardware do Jellyfin não vai funcionar.
Na criação da stack, aba Environment variables do Portainer:
| Variável | Obrigatória | Descrição |
|---|---|---|
FILEBOT_VNC_PASSWORD |
Sim | Senha de acesso à interface gráfica do FileBot |
YAMTRACK_SECRET |
Sim | Chave de assinatura do Django no Yamtrack. Gere com openssl rand -base64 48 |
YAMTRACK_REGISTRATION |
Não | True no primeiro boot para criar sua conta. Troque para False depois |
YAMTRACK_URLS |
Não | Origens públicas confiáveis, se for expor por proxy reverso. Ex.: https://yamtrack.exemplo.com |
PLEX_CLAIM |
Não | Token de plex.tv/claim, válido por 4 minutos. Só no primeiro boot |
PLEX_ADVERTISE_IP |
Não | Ex.: http://192.168.x.x:32400/. Ajuda o Plex a se anunciar na LAN |
Para gerar o segredo do Yamtrack:
openssl rand -base64 48Warning
Trocar o YAMTRACK_SECRET depois invalida as sessões de login. Gere uma vez e guarde junto dos
seus outros segredos.
Caution
Nunca escreva senha diretamente no YAML. O arquivo da stack acaba no Git, em backup e no export do Portainer.
- Portainer → Stacks → Add Stack
- Nome:
midia - Colar o conteúdo de
assets/stacks/midia.ymlno Web editor - Preencher as Environment variables da Parte 2
- Deploy the stack
Alternativa via SSH:
docker compose -f midia.yml up -d
Os serviços web ficam em uma rede bridge dedicada e se enxergam por nome. Ao configurar o
Radarr, o endereço do qBittorrent é qbittorrent, não o IP da máquina.
Isso importa: se a stack usar network_mode: bridge sem rede dedicada, cada serviço só alcança os
outros pelo IP do host. No dia em que o servidor mudar de IP (troca de roteador, DHCP, mudança de
faixa), todos os apontamentos quebram de uma vez.
Plex e Jellyfin são a exceção e ficam em network_mode: host, porque dependem de multicast para o
discovery na rede local e de acesso direto aos devices de vídeo.
Para os containers da rede bridge falarem com o Plex (que está na rede do host), a stack define
extra_hosts: host.docker.internal:host-gateway no Tautulli e no Seerr.
No sentido inverso, quando o Jellyfin (rede do host) precisa alcançar o Yamtrack (rede bridge com
porta publicada), o endereço é simplesmente http://localhost:8010.
Acesse http://192.168.x.x:8080.
Versões recentes geram uma senha temporária no log:
docker logs qbittorrent 2>&1 | grep -i "temporary password"Troque em Ferramentas → Opções → Interface Web.
Este passo é obrigatório com a rede midia-net e é a causa mais comum de "o Radarr não conecta no
qBittorrent" depois da migração.
Em Opções → Interface Web, na seção Segurança:
- Desmarcar "Habilitar validação do cabeçalho Host" (
Enable host header validation)
Sem isso, o qBittorrent devolve 401 Unauthorized para requisições que chegam com Host: qbittorrent.
Em Opções → Downloads:
| Configuração | Valor |
|---|---|
| Modo de gerenciamento padrão dos torrents | Automático |
| Quando a categoria do torrent for mudada | Re-alocar torrent |
| Quando o caminho padrão de salvamento mudar | Re-alocar torrents afetados |
| Caminho padrão de salvamento | /data/Downloads/torrents |
| Pré-alocar espaço em disco para todos os arquivos | Marcado |
Important
O modo Automático é o que faz o qBittorrent respeitar as pastas por categoria que o Radarr e o Sonarr enviam. No modo Manual, tudo cai na mesma pasta e a organização não acontece.
O Radarr e o Sonarr criam as categorias sozinhos no primeiro download. Se quiser adiantar, clique com o botão direito em Categorias → Adicionar categoria:
| Categoria | Caminho de salvamento |
|---|---|
radarr |
/data/Downloads/torrents/radarr |
tv-sonarr |
/data/Downloads/torrents/tv-sonarr |
Em Opções → Conexão, defina a porta de entrada como 62609 (a mesma publicada no YAML) e abra essa porta TCP e UDP no roteador. Sem redirecionamento, você só consegue conexões de saída e a velocidade despenca.
Acesse http://192.168.x.x:9696.
Settings → Indexers → + (em Indexer Proxies) → FlareSolverr:
| Campo | Valor |
|---|---|
| Name | FlareSolverr |
| Tags | flaresolverr |
| Host | http://flaresolverr:8191 |
Depois, em cada indexador que exija Cloudflare, adicione a tag flaresolverr.
Settings → Apps → + → Radarr:
| Campo | Valor |
|---|---|
| Sync Level | Full Sync |
| Prowlarr Server | http://prowlarr:9696 |
| Radarr Server | http://radarr:7878 |
| API Key | Radarr → Settings → General → API Key |
Repita para o Sonarr com http://sonarr:8989.
Com Full Sync, o Prowlarr cadastra, atualiza e remove indexadores no Radarr e no Sonarr sozinho.
Você nunca mais mexe em indexador dentro deles.
Indexers → Add Indexer. Filtre por Privacy: Public e Categories: Movies, TV.
Referência do que está em uso hoje nesta instalação (18 ativos):
1337x, Bangumi Moe, BitSearch, Internet Archive, Knaben, LimeTorrents, nekoBT,
NoNaMe Club, Nyaa.si, SubsPlease, sukebei.nyaa.si, The Pirate Bay, Torrent Downloads,
TorrentDownload, TorrentGalaxyClone, Uindex, UniOtaku, YTS.
Nyaa.si,SubsPlease,Bangumi Moe,nekoBTeUniOtakusão os que realmente entregam anime. Para filme e série em português,KnabeneBitSearchcostumam render mais que os genéricos.
Depois de adicionar, clique em Test All Indexers e remova os que falharem. Por fim, Sync App Indexers.
Tip
Não habilite tudo. Cada indexador é uma requisição a mais em cada busca. Passando de uns 20, a busca fica lenta e alguns indexadores começam a dar timeout.
Acesse http://192.168.x.x:7878.
Settings → Media Management → marcar Rename Movies e Replace Illegal Characters.
- Colon Replacement:
Delete - Standard Movie Format:
{Movie CleanTitle} {(Release Year)} {imdb-{ImdbId}} {edition-{Edition Tags}} {[Custom Formats]}{[Quality Full]}{[MediaInfo 3D]}{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[Mediainfo VideoCodec]}{-Release Group}
- Movie Folder Format:
{Movie CleanTitle} ({Release Year}) {imdb-{ImdbId}}
O {imdb-{ImdbId}} é o detalhe que mais economiza dor de cabeça: com o ID do IMDb no nome da pasta,
o Plex e o Jellyfin acertam o filme na primeira varredura, sem depender de heurística de título.
Ainda em Media Management, seção Importing:
| Configuração | Valor |
|---|---|
| Use Hard Links instead of Copy | Marcado |
| Skip Free Space Check | Marcado |
| Import Extra Files | Desmarcado |
Em Media Management → File Management → Recycling Bin, informe um caminho, por exemplo
/data/Downloads/lixeira.
Note
Neste servidor a lixeira está vazia hoje. Sem ela, quando o Radarr faz upgrade de qualidade, o arquivo antigo é apagado direto, sem rede de segurança. Com a lixeira configurada, você tem alguns dias para perceber que o "upgrade" ficou pior que o original.
Também em File Management: Propers and Repacks → Do not Prefer.
Settings → Media Management → Root Folders → adicionar /data/Filmes.
Warning
Limpeza necessária nesta instalação. Hoje o Radarr tem duas pastas raiz cadastradas:
/data/Filmes e /data/radarr/movies. Duas raízes fazem o Radarr espalhar filmes em dois
lugares dependendo de onde o item foi adicionado.
Antes de remover a raiz sobrando, verifique se há mídia nela:
ls -la /srv/midia/radarr/Se houver, mova para /srv/midia/Filmes/ e reaponte a pasta raiz dos filmes afetados pelo modo
de seleção em massa (ver quadro na Parte 7.1). Só então remova a raiz antiga.
Settings → Custom Formats → + → Import.
Os três essenciais, com os trash_id do TRaSH Guides:
| Formato | trash_id |
Pontuação | Para quê |
|---|---|---|---|
| BR-DISK | ed38b889b31be83fda192888e2286d83 |
-10000 |
Bloqueia releases ISO/BD completos, de 50 GB, que o Plex nem abre |
| 3D | b8cd450cbfa689c0259a01d9e29ba3d6 |
-10000 |
Bloqueia releases 3D (SBS, Half-OU) |
| Open Matte | 09d9dd29a0fc958f9796e65c2a8864b4 |
25 |
Prefere versões com o quadro completo, sem corte |
Tip
Pegue o JSON sempre atualizado em trash-guides.info/Radarr/Radarr-collection-of-custom-formats. Os regex mudam com o tempo, e um regex velho de BR-DISK deixa passar exatamente o que ele deveria bloquear. Quem quiser automatizar, o Recyclarr sincroniza os formatos do TRaSH direto para o Radarr e o Sonarr.
Caution
Criar o formato não bloqueia nada. Esta é a parte que mais confunde, e é onde a configuração costuma ficar pela metade.
O formato personalizado só define o que casar (o regex). Quem define o peso é o perfil de qualidade, numa tela completamente diferente (Parte 6.6). Um formato recém-criado nasce com pontuação 0 em todos os perfis, e pontuação 0 significa "tanto faz": o BR-DISK continua sendo baixado normalmente.
Ou seja, são dois passos obrigatórios:
- Settings → Custom Formats: criar o formato com o regex (define o "o quê")
- Settings → Profiles → editar o perfil: descer até Custom Formats e atribuir a pontuação (define o "quanto")
Se você abrir o perfil e vir 3D 0 e BR-DISK 0, os filtros estão inativos, mesmo com os
formatos criados e os regex corretos.
Qualquer formato com pontuação negativa nunca é baixado. É assim que você impede o servidor de encher com um único BD-REMUX de 80 GB.
Settings → Profiles → editar Any. A tela tem três blocos, e é comum configurar só o
primeiro.
Bloco 1: regras de upgrade (topo da tela)
| Campo | Valor sugerido | O que faz |
|---|---|---|
| Upgrades Allowed | marcado | Permite trocar por uma versão melhor depois |
| Upgrade Until | WEB 1080p ou Bluray-1080p |
Teto de qualidade. Chegou aqui, para de procurar |
| Minimum Custom Format Score | 0 |
Nota mínima aceita. Abaixo disso, não baixa |
| Upgrade Until Custom Format Score | 10000 |
Teto de nota. Serve para continuar melhorando por formato mesmo já no teto de qualidade |
| Minimum Custom Format Score Increment | 1 |
Ganho mínimo para valer a pena trocar o arquivo |
| Language | Any ou Original |
Original evita baixar dublagem por engano |
Bloco 2: qualidades (a lista com caixas)
Marque da melhor até o piso que você tolera. Ordem = preferência, o topo é o mais desejado.
Tip
Desmarque Remux-1080p, Remux-2160p, Bluray-2160p e Raw-HD se o espaço importa. Um
Remux tem de 40 a 80 GB e, nesta placa, ainda força transcode em quase todo cliente. Deixar
WEB 1080p como teto entrega arquivos de 2 a 5 GB que tocam em Direct Play.
Manter as qualidades baixas marcadas (CAM, TELESYNC, SDTV) só faz sentido com Upgrades
Allowed ligado: o Radarr baixa a porcaria agora e troca sozinho quando sair coisa melhor. Se
você prefere esperar, desmarque todas abaixo de WEB 720p.
Bloco 3: pontuação dos formatos personalizados (o final da tela, precisa rolar)
É aqui que os formatos da Parte 6.5 ganham efeito:
| Formato | Pontuação | Efeito |
|---|---|---|
| BR-DISK | -10000 |
Nunca baixa |
| 3D | -10000 |
Nunca baixa |
| Open Matte | 25 |
Prefere, mas aceita outros se não houver |
| HEVC | 1000 |
Prefere fortemente HEVC (economiza espaço, e o Jellyfin decodifica por hardware) |
| WEBRip Preference | 10 |
Leve preferência por WEBRip |
Warning
Qualquer formato deixado em 0 não faz nada. Se o seu BR-DISK e o 3D estiverem zerados, eles
não estão bloqueando release nenhum, por mais correto que esteja o regex.
Uma pontuação negativa só bloqueia de fato se for menor que o Minimum Custom Format Score.
Com o mínimo em 0, qualquer valor negativo já barra, e é por isso que -10000 é o exagero
proposital recomendado pelo TRaSH: garante o bloqueio mesmo somado a bônus de outros formatos.
Com upgrade ligado, um filme que só existe em CAM é baixado agora e substituído automaticamente quando sair o Bluray.
Para conteúdo dublado, existe um guia complementar do mesmo autor: Guia: filmes dublados automáticos no Radarr.
Settings → Download Clients → + → qBittorrent:
| Campo | Valor |
|---|---|
| Host | qbittorrent |
| Port | 8080 |
| Username | seu usuário |
| Password | sua senha |
| Category | radarr |
Em Completed Download Handling, marcar Remove Completed.
Note
Hoje esta instalação usa 192.168.68.9 como host. Depois de migrar para a rede midia-net, troque
pelo nome qbittorrent. Se der 401 Unauthorized, falta o passo 4.2.
Dá para o Radarr monitorar uma lista do Letterboxd e baixar tudo que você adicionar lá pelo celular.
- Crie a lista no Letterboxd
- Troque
letterboxd.comporletterboxd-list-radarr.onrender.comna URL. Isso gera um feed que o Radarr entende - Settings → Lists → + → Advanced → Custom Lists
| Campo | Valor |
|---|---|
| Enable Automatic Add | Marcado |
| Monitor | Movie Only |
| Search on Add | Marcado |
| Minimum Availability | Announced |
| Root Folder | /data/Filmes |
| List URL | a URL gerada |
Em Options → Clean Library Level: Remove Movie and Delete Files faz o filme sumir do
servidor quando você tira da lista. Útil com pouco espaço, perigoso se você esquecer que está ligado.
Acesse http://192.168.x.x:8989.
Settings → Media Management, marcar Rename Episodes e Replace Illegal Characters.
Há duas escolas aqui, e as duas funcionam. A diferença é o quanto de metadado você quer dentro do nome do arquivo.
Nomes curtos e legíveis. A informação técnica fica dentro do arquivo, não no nome.
| Campo | Valor |
|---|---|
| Formato do Episódio Padrão | S{Season:00}E{Episode:00} - {Episode Title} |
| Formato do episódio diário | {Series Title} - {Air-Date} - {Episode Title} |
| Formato do episódio de anime | S{Season:00}E{Episode:00} - {Episode Title} |
| Formato de Pasta das Séries | {Series Title} |
| Formato da Pasta da Temporada | Season {season:00} |
| Formato da Pasta para Especiais | Specials |
| Estilo de multiepisódio | Faixa Prefixada |
| Substituto para dois-pontos | Substituição inteligente |
Resultado: Steins;Gate/Season 01/S01E12 - Dogma in Event Horizon.mkv
Carrega qualidade, codec, canais de áudio e grupo de release no nome, o que ajuda a decidir sem abrir o arquivo e a diferenciar duas versões do mesmo episódio.
{Series TitleYear} - S{season:00}E{episode:00} - {Episode CleanTitle} [{Preferred Words }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}{[Mediainfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoCodec]}{-Release Group}
Para anime, o formato do TRaSH acrescenta {absolute:000} (numeração absoluta, que muitos grupos de
fansub usam) e {MediaInfo AudioLanguages}, que separa legendado de dublado:
{Series TitleYear} - S{season:00}E{episode:00} - {absolute:000} - {Episode CleanTitle} [{Preferred Words }{Quality Full}]{[MediaInfo VideoDynamicRangeType]}[{MediaInfo VideoBitDepth}bit]{[MediaInfo VideoCodec]}[{Mediainfo AudioCodec} { Mediainfo AudioChannels}]{MediaInfo AudioLanguages}{-Release Group}
Important
Independente do formato escolhido para o arquivo, coloque o ID externo no nome da pasta da série:
{Series TitleYear} {tvdb-{TvdbId}}
Sem isso, Plex e Jellyfin identificam a série adivinhando pelo título, e erram. É exatamente essa a causa de uma pasta de anime ser catalogada como um documentário da BBC, com pôster e sinopse errados: o scanner achou um título parecido no banco de dados e assumiu.
Com o ID no nome, não há adivinhação. O scanner lê o identificador e busca o registro exato.
Para séries e animes o Sonarr usa TVDB, então prefira {tvdb-{TvdbId}}. O Radarr usa
IMDb, e por isso a Parte 6.1 usa {imdb-{ImdbId}} nas pastas de filme.
O antigo Mass Editor saiu do menu lateral na versão 4. As ações em massa agora ficam atrás de um modo de seleção:
- Séries → botão Selecionar a Série na barra de ferramentas do topo
- Marque as séries, ou use Selecionar tudo
- Uma barra de ações aparece no rodapé da página:
| Ação no rodapé | Para que serve |
|---|---|
| Editar | É o antigo Mass Editor: Perfil de Qualidade, Pasta Raiz, Tipo de Série, Tags |
| Renomear Arquivos | Renomeia apenas os arquivos de episódio, nunca as pastas |
| Definir tags / Atualizar Monitoramento | O que o nome diz |
Caution
"Renomear Arquivos" não renomeia pastas, e é aí que quase todo mundo trava. O próprio modal
avisa: "deseja organizar todos os arquivos da N série selecionada?". Se você mudou o
Formato de Pasta das Séries e rodou o Organizar, os arquivos são renomeados e as pastas
continuam com o nome velho, sem o {tvdb-...}.
Para renomear as PASTAS, o caminho é outro, e a própria interface o descreve:
- Séries → Selecionar a Série → Selecionar tudo
- No rodapé, Editar
- Deixe tudo em "Sem alteração", exceto Pasta raiz
- Em Pasta raiz, escolha a mesma pasta em que as séries já estão (
/data/Animes) - Aplicar mudanças
A dica embaixo do campo confirma: "Mover séries para a mesma pasta raiz pode ser usado para renomear pastas de séries para corresponder ao título atualizado ou formato de nomenclatura".
Parece que não faz nada, mas o Sonarr recalcula o nome de cada pasta com o formato novo e move as
séries. Como origem e destino estão no mesmo sistema de arquivos, é um rename de inode:
instantâneo, mesmo com centenas de GB, e sem quebrar os hardlinks que o qBittorrent usa para
semear.
Resumindo qual botão usar:
| Você mudou... | Use |
|---|---|
| Formato do Episódio (nome do arquivo) | Renomear Arquivos |
| Formato de Pasta das Séries | Editar → Pasta raiz → a mesma pasta |
| Os dois | Primeiro a Pasta raiz, depois Renomear Arquivos |
Feito isso, rode Update Library no Plex e Atualizar metadados no Jellyfin.
Tip
Como as séries normais e os animes estão em raízes diferentes, repita o processo uma vez por raiz,
filtrando a lista antes de selecionar. Selecionar séries de /data/Animes e apontar para
/data/Series moveria tudo de lugar.
- Use Hard Links instead of Copy: marcado
- Root Folders:
/data/Seriese/data/Animes
Ao adicionar uma série, escolha Series Type: Anime para animes, o que faz o Sonarr usar o formato de nomenclatura de anime e a numeração absoluta.
Warning
Limpeza necessária nesta instalação. O Sonarr tem hoje quatro pastas raiz cadastradas:
/data/Series, /data/Animes, /data/sonarr/tv e /data/sonarr/anime. Aplique o mesmo
procedimento da seção 6.4: verifique /srv/midia/sonarr/, mova o que houver e use o
modo de seleção em massa antes de remover as raízes antigas.
Igual ao Radarr, com Category: tv-sonarr.
Acesse http://192.168.x.x:6767.
Settings → Sonarr: habilitar, Address sonarr, Port 8989, API Key do Sonarr.
Settings → Radarr: habilitar, Address radarr, Port 7878, API Key do Radarr.
Settings → Languages:
- Languages Filter:
Brazilian Portuguese - Add New Profile → nome
Português→ Add Language →Brazilian Portuguese - Em Default Settings, habilitar Series e Movies, ambos com o perfil
Português
Settings → Subtitles:
A tela é longa, então vai por blocos.
Subtitle File Options
| Configuração | Valor | Por quê |
|---|---|---|
| Subtitle Folder | AlongSide Media File |
A legenda fica ao lado do vídeo, como Plex e Jellyfin esperam |
| Encode Subtitles To UTF-8 | ligado | Evita acento quebrado em legenda pt-BR |
| Change Subtitle File Permission (chmod) | 0644 |
Ver aviso abaixo |
Warning
0640 é arriscado. Com esse valor só o dono e o grupo leem o arquivo. Como Bazarr, Plex e
Jellyfin rodam todos com UID 1000, funciona por coincidência, até você mexer em alguma
permissão ou adicionar um serviço com outro UID. Use 0644.
Embedded Subtitles Handling
| Configuração | Valor | Por quê |
|---|---|---|
| Treat Embedded Subtitles as Downloaded | ligado | Não baixa legenda se o arquivo já tem uma |
| Parser | ffprobe |
Mais rápido que o mediainfo e já vem instalado |
| Ignore Embedded PGS Subtitles | ligar | Ver dica abaixo |
| Ignore Embedded VobSub Subtitles | ligar | Mesmo motivo do PGS |
| Show Only Desired Languages | ligado | Esconde o que não interessa |
Tip
Ligue "Ignore Embedded PGS/VobSub". As duas são legenda em imagem, não em texto. Para exibir, o player precisa queimar a legenda no vídeo, e isso força transcode mesmo num arquivo que seria Direct Play.
Ignorando as embutidas, o Bazarr entende que falta legenda de texto e baixa um .srt externo, que
não força transcode nenhum. Nesta placa isso é a diferença entre assistir e engasgar.
Performance / Optimization
| Configuração | Valor | Observação |
|---|---|---|
| Adaptive Searching | ligado | Evita martelar provedores atrás de legenda que não existe |
| Search Enabled Providers Simultaneously | ligado | A tela desaconselha em "low powered devices", mas com 8 núcleos aqui é tranquilo |
| Skip video file hash calculation | desligado | O hash é o que dá o melhor casamento de legenda |
Sub-Zero Modifications
| Configuração | Valor | Por quê |
|---|---|---|
| OCR Fixes | ligado | Corrige I/l/1 trocados em legenda vinda de OCR |
| Common Fixes | ligar | Arruma espaçamento e pontuação. Não há motivo para deixar desligado |
| Hearing Impaired | desligado | Só ligue para remover marcações de som |
| Fix Uppercase | desligado | Ligue apenas se pegar legenda toda em caixa alta |
Audio Synchronization, a parte que mais resolve na prática
| Configuração | Valor | Por quê |
|---|---|---|
| Enable Automatic Subtitles Audio Synchronization | ligado | Alinha a legenda com o áudio |
| Synchronization Reference | Use Audio Track as Reference |
Mais confiável que usar outra legenda |
| Do Not Fix Framerate Mismatch | DESLIGAR | Ver aviso abaixo |
| Golden-Section Search | ligado | Busca o melhor ajuste |
| Max Offset Seconds | 60 |
Suficiente para o desalinhamento normal |
Caution
"Do Not Fix Framerate Mismatch" ligado atrapalha justamente o pior caso de dessincronia.
Quando a legenda foi feita para uma versão em 23,976 fps e o arquivo é 25 fps (ou o contrário), o erro cresce ao longo do episódio: começa certo e termina minutos fora. Corrigir isso exige ajustar o framerate, que é exatamente o que essa opção impede.
Desligue. O nome confunde: você quer sim que ele corrija o framerate.
Translating (opcional)
Com um tradutor selecionado e score alto, o Bazarr traduz por máquina quando não encontra legenda em português. Resolve a ausência, mas a qualidade fica bem abaixo de uma legenda humana. Se preferir só legenda de verdade, deixe o tradutor vazio.
A sincronização automática é o recurso que mais vale a pena aqui: o Bazarr alinha o tempo da legenda com o áudio do arquivo, resolvendo o clássico "a legenda está 3 segundos adiantada".
Settings → Providers → + → OpenSubtitles.com (o .org foi descontinuado). Crie a conta
no site e informe usuário e senha.
Acesse http://192.168.x.x:5055.
O Seerr é o fork comunitário do Overseerr. É a interface que você compartilha com a família: eles pesquisam, clicam em "Request", e o pedido cai direto no Radarr ou no Sonarr.
- Login com a conta Plex
- Settings → Plex: hostname
host.docker.internal, porta32400 - Settings → Services → Radarr: hostname
radarr, porta7878, API Key, Root Folder/data/Filmes - Settings → Services → Sonarr: hostname
sonarr, porta8989, API Key, Root Folder/data/Series - Settings → Users: crie contas para a família com permissão de request, mas sem auto-aprovação, se quiser dar o aval antes de cada download
O hostname do Plex é
host.docker.internalporque o Plex roda emnetwork_mode: hostenquanto o Seerr está na redemidia-net. A stack já declara oextra_hostsque faz esse nome resolver.
Acesse http://192.168.x.x:32400/web.
Se o servidor não aparecer vinculado à sua conta, pegue um token em
plex.tv/claim e coloque em PLEX_CLAIM nas Environment variables do
Portainer. O token vale 4 minutos, então gere e faça o redeploy na sequência.
| Biblioteca | Tipo | Pasta |
|---|---|---|
| Filmes | Movies | /data/Filmes |
| Séries | TV Shows | /data/Series |
| Animes | TV Shows | /data/Animes |
Configurações → Biblioteca:
| Configuração | Estado |
|---|---|
| Digitalizar minha biblioteca automaticamente | Habilitado |
| Executar varredura parcial quando detectar alterações | Habilitado |
| Escanear minha biblioteca periodicamente | Desabilitado |
| Esvaziar lixeira automaticamente após cada varredura | Habilitado |
| Permitir exclusão de mídia | Desabilitado |
| Executar tarefas de varredura em prioridade menor | Habilitado |
Desligar a varredura periódica e deixar só a detecção de alterações economiza bastante CPU numa placa ARM.
Gerenciar → Bibliotecas → Editar → Avançado, para Filmes:
- Scanner e Agente:
Plex Movie - Usar recursos locais: habilitado
- Metadados locais preferidos: desabilitado
- Coleções:
Hide collections but show their items
Para Séries e Animes:
- Scanner e Agente:
Plex TV Series - Ordem dos episódios:
The Movie Database - Usar títulos da temporada: habilitado
Caution
O Plex não faz transcode por hardware nesta placa. São dois bloqueios independentes:
- A aceleração do Plex usa Intel Quick Sync, AMD ou NVIDIA. O RK3588 tem GPU Mali e VPU RKMPP, que o Plex não implementa.
- Mesmo em hardware compatível, é recurso exclusivo de assinantes do Plex Pass.
Mapear /dev/dri e definir PLEX_HW_TRANS_MAX não muda nada: o Plex simplesmente ignora. Foi
por isso que essas linhas saíram do YAML.
Na prática, isso significa que o Plex desta placa depende de Direct Play: o arquivo precisa ser reproduzido sem conversão. Para conseguir isso:
- Prefira releases em H.264 quando o cliente for antigo (TV de linha básica, PS4, navegador)
- Evite HDR se a TV for SDR, porque o tone-mapping força transcode
- Evite legenda PGS/VobSub embutida, porque queimar legenda na imagem força transcode. Legenda
externa
.srt(o que o Bazarr baixa) não força - Nos apps cliente, deixe a qualidade em Original / Maximum
Se o vídeo travar e engasgar, é quase certo que o Plex entrou em transcode por software. Confirme na aba Atividade do painel: aparece "Transcode" em vez de "Direct Play".
Para transcode acelerado de verdade nesta placa, use o Jellyfin.
Acesse http://192.168.x.x:8096.
Esta é a diferença técnica real entre os dois players nesta placa. A imagem
nyanmisaka/jellyfin:latest-rockchip traz um jellyfin-ffmpeg compilado com o pipeline completo
RKMPP (decode/encode pela VPU) e RGA (scaling por hardware) do RK3588.
Note
A imagem oficial jellyfin/jellyfin não tem esse suporte. Precisa ser a latest-rockchip do
nyanmisaka, e ela é exclusiva para arm64.
As mesmas pastas do Plex: /data/Filmes, /data/Series, /data/Animes.
Se a biblioteca mostra 進撃の巨人 em vez de "Attack on Titan", não é bug: o Jellyfin está pedindo ao TMDB o título no idioma configurado na biblioteca, e o padrão é o idioma original da obra.
A configuração não fica no perfil do usuário nem no idioma da interface, e existe em dois níveis. É por isso que ajustar só um deles não resolve.
Nível 1, o padrão do servidor
Painel → Bibliotecas → Metadados:
| Campo | Valor |
|---|---|
| Idioma | Portuguese (Brazil) |
| País/Região | Brazil |
A própria tela avisa: "Estas são suas configurações padrão e podem ser personalizadas por biblioteca".
Nível 2, o override de cada biblioteca
Important
É aqui que os animes ficam em japonês. Cada biblioteca guarda o próprio idioma, e ele
sobrescreve o padrão do servidor. Uma biblioteca de anime costuma vir com Japanese, porque
foi o idioma detectado ou escolhido na criação.
Painel → Bibliotecas → clicar na biblioteca (ou no ⋮ → Gerenciar biblioteca) → rolar até Configurações da Biblioteca:
| Campo | Trocar para |
|---|---|
| Idioma preferido de download | Portuguese (Brazil) |
| País/Região | Brazil |
O nome do campo confunde: "Idioma preferido de download" não tem a ver com baixar arquivos, e sim com o idioma dos metadados que o Jellyfin busca no TMDB.
Repita para cada biblioteca: Filmes, Séries e Animes.
Aplicar no que já existe
Mudar o idioma não reescreve o que já foi baixado. O aviso no topo da própria tela diz isso:
"Alterações nas configurações de metadados e artes baixados serão aplicadas apenas a novos conteúdos adicionados a sua biblioteca. Para aplicar as alterações nos títulos existentes, será necessário atualizar os metadados deles manualmente."
Então, depois de salvar:
- Painel → Bibliotecas → ⋮ na biblioteca → Atualizar metadados
- Escolha "Substituir todos os metadados" (
Replace all metadata)
Sem marcar essa opção, o Jellyfin preserva o que já tem e nada muda.
Warning
"Substituir todos os metadados" apaga edições manuais que você tenha feito, inclusive as correções por "Identificar". Por isso vale fazer a limpeza de identificação depois dessa atualização, e não antes.
Tip
Nem todo anime tem título em português no TMDB. Quando não houver tradução, o Jellyfin cai para o idioma original de novo, e não há o que fazer pelo painel. Nesses casos, edite o item e ajuste o título manualmente, ou aceite o inglês como segundo idioma.
O sintoma é inconfundível: um anime aparece com pôster e sinopse de um documentário da BBC, e o episódio "a seguir" mostra o nome certo em português. Isso significa que o item da biblioteca está casado com o registro errado no banco de metadados, mesmo com os arquivos corretos.
A causa quase sempre é a mesma: a pasta da série não tem o ID externo no nome, então o scanner tentou adivinhar pelo título e acertou outra coisa. Ver o aviso da Parte 7.1.
Correção pontual, item a item:
- Abrir a série → menu ⋮ → Identificar
- Preencher o TVDB ID ou o TMDB ID da série correta, ou buscar pelo nome
- Confirmar. O Jellyfin refaz os metadados daquele item
Correção definitiva, para não voltar a acontecer:
- No Sonarr, mudar o Series Folder Format para incluir
{tvdb-{TvdbId}}(Parte 7.1) - Séries → Selecionar a Série → selecionar tudo → Editar → Pasta raiz = a mesma pasta atual (isso renomeia as pastas, ver Parte 7.1)
- No Jellyfin, Atualizar metadados com Substituir todos os metadados marcado
Note
Enquanto as pastas não tiverem ID, todo item novo continua sujeito ao mesmo erro. Corrigir pelo "Identificar" resolve um de cada vez, mas não previne o próximo.
Painel → Reprodução → Transcodificação:
| Configuração | Valor |
|---|---|
| Aceleração de hardware | Rockchip MPP (RKMPP) |
| Decodificação por hardware | H264, HEVC, VP9, AV1, HEVC 10bit, VP9 10bit |
| Decodificação, opcionais | MPEG1, MPEG2, MPEG4, VP8 (a VPU também faz, útil para material antigo) |
| Ativar codificação por hardware | Marcado |
| Permitir codificação HEVC | Marcado |
| Permitir codificação AV1 | DESMARCADO (ver aviso abaixo) |
| Ativar mapeamento de tons | Marcado, algoritmo BT.2390 |
| Local de transcodificação | /cache/transcodes, que a stack monta como tmpfs |
Caution
Deixe "Permitir codificação em formato AV1" desmarcado. O RK3588 decodifica AV1, mas não codifica. Confira você mesmo:
docker exec jellyfin /usr/lib/jellyfin-ffmpeg/ffmpeg -hide_banner -encoders | grep rkmppA saída lista apenas três encoders de hardware:
V..... h264_rkmpp Rockchip MPP H264 encoder
V..... hevc_rkmpp Rockchip MPP HEVC encoder
V..... mjpeg_rkmpp Rockchip MPP MJPEG encoder
Não existe av1_rkmpp. Com a opção marcada, o Jellyfin cai no libsvtav1 por software, e
numa placa ARM o transcode nunca acompanha a reprodução. A própria tela avisa: "O Jellyfin usará
codificação por software quando a aceleração de hardware para o formato selecionado não estiver
disponível."
Para conferir a lista de decoders que a sua VPU realmente entrega:
docker exec jellyfin /usr/lib/jellyfin-ffmpeg/ffmpeg -hide_banner -decoders | grep rkmppNo RK3588 saem dez: av1, h263, h264, hevc, mjpeg, mpeg1, mpeg2, mpeg4, vp8 e vp9.
Tip
Transcode em RAM. A stack monta /cache/transcodes como tmpfs de 2 GB. Os arquivos
temporários de transcode são descartáveis e escrevê-los no NVMe só desgasta o SSD à toa. Se você
transcodifica 4K com frequência, aumente o size no YAML, lembrando que sai da RAM da placa.
Reproduza um arquivo forçando qualidade menor que a original (para provocar transcode) e observe:
# O log deve mostrar rkmpp na linha de comando do ffmpeg
docker logs jellyfin 2>&1 | grep -i rkmpp | tail -5
# Uso de CPU durante o transcode: com HW fica baixo, com software vai a 100% nos 8 cores
docker stats jellyfin --no-streamSe aparecer -hwaccel rkmpp e a CPU ficar abaixo de uns 30%, a aceleração está ativa.
O melhor indicador é o speed= do próprio FFmpeg. Rode os dois e compare:
ARQ="/data/Animes/ALGUMA_SERIE/ALGUM_EPISODIO.mkv"
# Hardware: decode RKMPP -> RGA -> encode RKMPP
docker exec jellyfin /usr/lib/jellyfin-ffmpeg/ffmpeg -hide_banner -nostats -loglevel info \
-init_hw_device rkmpp=rk -hwaccel rkmpp -hwaccel_output_format drm_prime \
-i "$ARQ" -t 60 -an -vf "scale_rkrga=w=1280:h=720:format=nv12" \
-c:v h264_rkmpp -b:v 3M -f null - 2>&1 | grep -E "^frame=" | tail -1
# Software, para comparar
docker exec jellyfin /usr/lib/jellyfin-ffmpeg/ffmpeg -hide_banner -nostats -loglevel info \
-i "$ARQ" -t 60 -an -vf "scale=1280:720" \
-c:v libx264 -preset veryfast -b:v 3M -f null - 2>&1 | grep -E "^frame=" | tail -1Medição real nesta placa, transcodificando 60 s de HEVC 1080p 10-bit para H.264 720p:
| Modo | fps | speed |
|---|---|---|
| Hardware (RKMPP + RGA) | 664 | 27,7x |
| Software (libx264 veryfast) | 24 | 1,02x |
O número que realmente importa é o 1,02x do software: o transcode mal empatava com a reprodução em
tempo real, então qualquer seek, segundo cliente ou tarefa concorrente já causava engasgo. Com a VPU
sobra folga de 27 vezes.
Tip
O rga_api version 1.10.4 que aparece no início da saída é informativo, não é erro: significa que
a biblioteca de scaling por hardware inicializou.
Se o teste de hardware falhar com Unsupported input pixel format 'nv15', não é defeito: o decode de
HEVC 10-bit no Rockchip devolve nv15, e o encoder só aceita nv12. É exatamente para isso que
serve o filtro scale_rkrga=...:format=nv12 no meio do comando. O Jellyfin monta essa conversão
sozinho, então isso só aparece em teste manual mal montado.
Este é o erro que trava o transcode por hardware e engana quem procura a causa, porque parece permissão de device e não é.
Sintoma no navegador: "Erro na Reprodução: a reprodução falhou devido a um erro fatal do player". No log do FFmpeg:
[hevc_rkmpp @ ...] Failed to init MPP context: -1
[dec:hevc_rkmpp @ ...] Error while opening decoder: Generic error in an external library
O que não resolve, tudo testado nesta placa:
| Tentativa | Resultado |
|---|---|
Mapear os 5 devices e usar group_add: [44, 105] |
falha |
Rodar o container como root (docker exec -u 0) |
falha |
Montar /dev inteiro (-v /dev:/dev) |
falha |
Fazer bind de /sys/firmware/devicetree/base em /proc/device-tree |
falha |
privileged: true |
funciona |
A librockchip_mpp precisa de um acesso que o cgroup de devices do Docker bloqueia, e rodar como
root dentro do container não contorna cgroup. É por isso que o mantenedor da imagem responde
exatamente isto em jellyfin/jellyfin#12174:
This is usually a permissions issue. The easiest way to get around this is to use sudo and
--privilegedin docker.
Warning
privileged: true remove o isolamento de dispositivos e capabilities desse container. É uma
concessão real de segurança, e por isso ela está apenas no Jellyfin, nunca nos demais serviços.
O container continua rodando como user: "1000:1000", então não vira root. Se você não usa
transcode (todos os seus clientes fazem Direct Play), pode remover a linha.
Para validar sem mexer na stack que está no ar:
sudo docker run --rm --privileged --user 1000:1000 \
-v /srv/midia:/data:ro \
--entrypoint /usr/lib/jellyfin-ffmpeg/ffmpeg nyanmisaka/jellyfin:latest-rockchip \
-hide_banner -loglevel error -init_hw_device rkmpp=rk -hwaccel rkmpp \
-i "/data/Filmes/ALGUM_ARQUIVO.mkv" -t 2 -f null -Saída vazia significa que o RKMPP inicializou.
Se o app do iPhone reproduz normalmente e o navegador dá erro, o transcode é a única diferença:
- O iOS decodifica HEVC nativamente, então o Jellyfin entrega o arquivo sem tocar nele (Direct Play) e o RKMPP nem é chamado
- O navegador não reproduz HEVC, então o Jellyfin precisa transcodificar, o RKMPP falha e a reprodução morre
O sintoma "o vídeo volta ao começo do episódio em vez de continuar" é consequência disso: quando o transcode falha, a sessão morre antes de reportar a posição, e o Jellyfin não tem o que salvar. Depois de corrigir o transcode, o resume volta a funcionar também no navegador.
Se o erro for explicitamente "Permission denied" nos devices:
# Os devices precisam pertencer ao grupo video
ls -l /dev/mpp_service /dev/rga /dev/mali0
# Confirmar os GIDs e conferir contra o group_add do YAML
getent group video renderAcesse http://192.168.x.x:8181. Na configuração inicial, aponte para o Plex:
| Campo | Valor |
|---|---|
| Plex IP/Host | host.docker.internal |
| Port | 32400 |
O Yamtrack é um rastreador de mídia self-hosted. Ele guarda o que você assistiu, com nota, progresso por episódio, datas e rewatches, e recebe os eventos automaticamente por webhook do Jellyfin, do Plex e do Emby.
Note
Por que ele está aqui no lugar do PlexTraktSync. Em julho de 2026 o Trakt passou a exigir
assinatura VIP para criar aplicativos OAuth, e apagou os apps de contas gratuitas mesmo tendo
dito que as conexões existentes seriam mantidas. O sintoma era o container em crash loop com
invalid_grant: session not found, e o Trakt respondendo invalid_client: client not found na
tentativa de reautenticar.
Não havia correção possível do lado do projeto, como discutido em Taxel/PlexTraktSync#2548. A diferença de fundo é que o Yamtrack guarda o histórico na sua própria placa, então nenhuma mudança de política de terceiros derruba o serviço de novo.
Ele usa Redis para tarefas em segundo plano, por isso a stack tem dois containers: yamtrack e
yamtrack-redis.
Tip
Quer continuar no Trakt mesmo sem VIP? Use o plugin do Jellyfin. A restrição de julho de 2026 atinge apenas quem precisa criar um aplicativo OAuth, que é o caso do PlexTraktSync.
O plugin Trakt para Jellyfin embute o client ID do próprio plugin: você só autoriza por device code, sem criar app nenhum e sem assinatura. Instale em Painel → Plugins → Catálogo → Trakt.
Os dois convivem bem: o plugin mantém seu perfil público do Trakt atualizado, e o Yamtrack guarda a cópia que não depende de ninguém.
Se o log do Jellyfin mostrar isto, não é problema de autenticação:
Trakt.Api.TraktApi: Exception handled in PostToTrakt
System.Net.Http.HttpRequestException: Response status code does not indicate success: 422
at Trakt.Api.TraktApi.SendEpisodeStatusUpdateAsync(...)
422 Unprocessable Entity significa que o Trakt entendeu a requisição e recusou o conteúdo. As
duas causas comuns, e as duas são sintoma de outro problema:
- A reprodução parou em
0 ms. ProcurePlayback stopped ... Stopped at 0 mslogo acima no log. Um scrobble com posição zero é inválido para o Trakt. Isso acontece quando o transcode falha, ou seja, é o problema da Parte 11.4 aparecendo em outro lugar - O item está identificado errado, então os IDs enviados não casam com nada no Trakt. Ver Parte 11.1
Antes de mexer no plugin, confira o token em /srv/jellyfin/config/plugins/configurations/Trakt.xml:
sudo grep -E "AccessTokenExpiration|LinkedMbUserId" \
/srv/jellyfin/config/plugins/configurations/Trakt.xmlSe a data de expiração estiver no futuro, a autenticação está boa e o 422 vem de uma das duas causas acima.
Acesse http://192.168.x.x:8010.
- Crie sua conta na tela de cadastro
- Depois de criada, troque
YAMTRACK_REGISTRATIONparaFalsenas Environment variables do Portainer e redeploy. Isso fecha o cadastro para estranhos, e você continua podendo criar contas pelo painel administrativo
O Jellyfin envia um webhook ao Yamtrack sempre que você assiste algo.
- No Yamtrack, abra as configurações do seu usuário e copie a URL de webhook do Jellyfin.
Ela tem o formato
/webhook/jellyfin/<token>, onde o token identifica a sua conta - No Jellyfin, vá em Painel → Plugins → Catálogo e instale o plugin Webhook
- Reinicie o Jellyfin:
docker restart jellyfin - Em Painel → Plugins → Webhook, adicione um Generic Destination com a URL
http://localhost:8010/webhook/jellyfin/SEU_TOKEN
O endereço é
localhost:8010porque o Jellyfin roda emnetwork_mode: hoste o Yamtrack publica a porta8010nesse mesmo host. Não useyamtrack:8000: esse nome só resolve dentro da redemidia-net, e o Jellyfin não está nela.
Caution
Sem template, o webhook não funciona. O Generic Destination monta o corpo da requisição a partir de um template Handlebars. Deixando em branco, o Jellyfin faz o POST com corpo vazio e o Yamtrack responde:
Notification failed with response status code BadRequest: Missing payload
Do outro lado, o log do Yamtrack mostra Missing payload in Jellyfin webhook request e 400.
O Yamtrack espera este formato, com o objeto Item aninhado:
{
"Event": "Stop",
"Item": {
"Type": "Episode",
"Name": "...",
"SeriesName": "...",
"ParentIndexNumber": 1,
"IndexNumber": 12,
"ProductionYear": 2021,
"ProviderIds": { "Tmdb": "...", "Imdb": "...", "Tvdb": "..." },
"UserData": { "Played": true }
}
}Eventos aceitos: Play, Stop, MarkPlayed e MarkUnplayed.
Em Notification Type marque Playback Stop, em Item Type marque apenas Episodes, e cole
no campo de template:
Crie um segundo destination, com Item Type apenas Movies. Filme não tem temporada nem
episódio, e deixar esses campos vazios geraria um JSON inválido:
Nos dois, use o User Filter para registrar só o que você assiste, e não o que a família vê.
curl -s -o /dev/null -w "HTTP %{http_code}\n" \
-X POST "http://localhost:8010/webhook/jellyfin/SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"Event":"MarkPlayed","Item":{"Type":"Episode","Name":"Teste",
"SeriesName":"Dr. Stone","ParentIndexNumber":1,"IndexNumber":1,
"ProductionYear":2019,"ProviderIds":{"Tmdb":"86031"},
"UserData":{"Played":true}}}'HTTP 200 significa formato aceito. Acompanhe o outro lado com:
docker logs -f yamtrack 2>&1 | grep -i webhookUma requisição bem processada aparece como Received webhook for tv: Dr. Stone S01E01.
| Resposta | Significado |
|---|---|
400 Missing payload |
Template vazio ou ausente |
500 com Tvdb error: NotFoundException |
O payload chegou certo, mas os IDs não casam com nada |
504 |
O Yamtrack ainda está buscando metadados. Nesta placa, a primeira consulta de um item novo é lenta e pode estourar o tempo do proxy |
Important
O 500 com NotFoundException amarra com a Parte 11.1: se a série está identificada errada no
Jellyfin, os ProviderIds enviados apontam para outra obra e o Yamtrack não acha o episódio.
Corrigir a identificação, e colocar o ID no nome da pasta pelo Sonarr, é pré-requisito para o
rastreamento funcionar de forma confiável.
O endpoint existe (/webhook/plex/<token>), mas há uma barreira do lado do Plex:
Warning
Webhooks do Plex são recurso exclusivo de assinantes do Plex Pass. Sem a assinatura, o menu de webhooks nem aparece nas configurações da conta. É a mesma barreira comercial que impede o transcode por hardware (ver Parte 10.4).
Se você tem Plex Pass, o caminho é Configurações da conta → Webhooks → Add Webhook, com a
URL http://localhost:8010/webhook/plex/SEU_TOKEN.
Se não tem, o rastreamento automático fica só pelo Jellyfin, o que é mais um motivo para concentrar a reprodução nele nesta placa.
Você não perde o que já tinha, e não precisa de API key nem de VIP para isso.
- Exporte seus dados em https://app.trakt.tv/settings/data
- No Yamtrack, vá em Importar e escolha a origem Trakt
O Yamtrack aceita duas rotas: informar o nome de usuário de um perfil público do Trakt, que dispensa qualquer credencial, ou autorizar por OAuth. Além do Trakt, ele importa de Simkl, MyAnimeList, AniList, Kitsu, IMDb, Steam e Goodreads, e aceita CSV.
Tip
Se o seu perfil do Trakt for privado, torne-o público por alguns minutos para usar a rota simples, e depois volte a fechá-lo.
| Caminho | Conteúdo |
|---|---|
/srv/yamtrack/db |
Banco SQLite com todo o seu histórico |
/srv/yamtrack/redis |
Fila de tarefas, descartável |
A stack usa bind mount em vez de volume nomeado justamente para que o banco entre nos snapshots
do Timeshift. Volumes nomeados vivem em /var/lib/docker, que o Timeshift exclui internamente.
Ver ./orangepi5-backup-restore.md.
Acesse http://192.168.x.x:5800 e informe a senha definida em FILEBOT_VNC_PASSWORD.
O FileBot é a ferramenta manual para o que os *arrs não conseguiram identificar: coleções antigas,
arquivos com nome bagunçado, mídia importada de outro servidor. A biblioteca aparece em /storage
dentro dele.
Caution
A interface do FileBot dá acesso de escrita a toda a biblioteca. Não exponha a porta 5800 à
internet, e use uma senha forte. Não deixe o valor no YAML.
Todos os serviços seguem tags móveis (:latest). Um redeploy comum reaproveita o cache e não
atualiza nada.
No Portainer: Stacks → midia → Re-pull image and redeploy.
Via SSH:
docker compose -f midia.yml pull && docker compose -f midia.yml up -dTip
O Plex quebra compatibilidade com apps antigos de vez em quando, e o Sonarr teve migrações de banco pesadas entre versões maiores. Antes de atualizar, tire um snapshot manual do Timeshift:
sudo timeshift --create --comments "antes de atualizar a stack midia"O que realmente importa nesta stack não são os arquivos de vídeo (esses você baixa de novo), e sim a configuração: indexadores, perfis de qualidade, formatos personalizados, histórico, chaves de API e o banco de metadados do Plex.
Tudo isso vive em /srv/<serviço>, no disco do sistema, e é coberto pelos snapshots do Timeshift.
| Caminho | Conteúdo | No Timeshift? |
|---|---|---|
/srv/radarr/appdata |
Banco, perfis, formatos, histórico | Sim |
/srv/sonarr/appdata |
Idem, para séries | Sim |
/srv/prowlarr/config |
Indexadores e apps | Sim |
/srv/qbittorrent/config |
Torrents ativos, categorias, preferências | Sim |
/srv/bazarr/appdata |
Provedores e perfis de idioma | Sim |
/srv/overseerr/config |
Usuários e requisições do Seerr | Sim |
/srv/plex/config |
Biblioteca, metadados, histórico | Sim |
/srv/jellyfin/config |
Biblioteca e usuários | Sim |
/srv/yamtrack/db |
Histórico de exibição (SQLite) | Sim |
/srv/midia |
Os arquivos de vídeo | Não (excluído de propósito) |
💾 O procedimento completo, incluindo o que fazer se a placa queimar, está em
./orangepi5-backup-restore.md.
| Sintoma | Causa provável | Solução |
|---|---|---|
Radarr/Sonarr: 401 Unauthorized no qBittorrent |
Validação de cabeçalho Host ativa | qBittorrent → Opções → Interface Web → desmarcar host header validation |
| Import cai para cópia e o disco enche | Downloads e biblioteca em volumes Docker diferentes | Usar mount único /srv/midia:/data em todos os containers |
find /srv/midia -links +1 não retorna nada |
Hardlink desligado nos *arrs |
Marcar "Use Hard Links instead of Copy" no Radarr e no Sonarr |
Indexador dá Cloudflare protection detected |
Falta o FlareSolverr no indexador | Adicionar a tag flaresolverr ao indexador no Prowlarr |
| Nada baixa, mas a busca encontra resultados | Formato personalizado com pontuação negativa demais | Conferir Custom Formats: nota abaixo de 0 bloqueia o download |
Torrent fica em Stalled para sempre |
Porta de entrada fechada | Redirecionar 62609 TCP/UDP no roteador e conferir a porta no qBittorrent |
| Vídeo engasga no Plex | Transcode por software | Ver Parte 10.4. Use Direct Play ou migre para o Jellyfin |
| Jellyfin: "Permission denied" nos devices | GID errado no group_add |
getent group video render e ajustar o YAML |
| Jellyfin não abre, mas o container está healthy | Porta 8096 bloqueada pelo UFW (só afeta network_mode: host) |
sudo ufw allow 8096/tcp. Ver Parte 1.5 |
| Jellyfin transcodifica AV1 e trava | "Permitir codificação AV1" marcado | Desmarcar. O RK3588 decodifica AV1 mas não codifica. Ver Parte 11.2 |
| Jellyfin: "Erro na Reprodução" só no navegador | Failed to init MPP context: -1 no transcode |
Adicionar privileged: true ao serviço. Ver Parte 11.4 |
| Vídeo volta ao começo em vez de continuar | A sessão morre junto com o transcode e não salva a posição | Mesma correção da Parte 11.4 |
| Toca no celular mas falha no navegador | iOS faz Direct Play, navegador força transcode | Ver Parte 11.5 |
| Jellyfin mostra títulos em japonês | A biblioteca tem override de idioma sobre o padrão do servidor | Trocar "Idioma preferido de download" na biblioteca. Ver Parte 11.1 |
| Série identificada como outra obra | Pasta sem ID externo, o scanner adivinha pelo título | Ver Parte 11.1 e o aviso da Parte 7.1 |
| Mudei o formato da pasta e nada foi renomeado | "Renomear Arquivos" só mexe em arquivos, não em pastas | Editar → Pasta raiz → a mesma pasta atual. Ver Parte 7.1 |
| Formato personalizado não bloqueia nada | Pontuação 0 no perfil de qualidade |
Criar o formato é só metade, pontue em Profiles. Ver Partes 6.5 e 6.6 |
| Legenda dessincroniza ao longo do episódio | "Do Not Fix Framerate Mismatch" ligado no Bazarr | Desligar. Ver Parte 8.3 |
| Arquivo com legenda embutida sempre transcodifica | Legenda PGS/VobSub é imagem e precisa ser queimada no vídeo | Ligar "Ignore Embedded PGS/VobSub" no Bazarr. Ver Parte 8.3 |
| Yamtrack não registra o que você assiste | Webhook do Jellyfin não configurado ou token errado | Ver Parte 12.2.2. Conferir com docker logs yamtrack |
Yamtrack: DisallowedHost ou erro de CSRF |
Origem não confiável no Django | Preencher YAMTRACK_URLS com o endereço usado no navegador |
Yamtrack não sobe: SECRET ausente |
Variável obrigatória não definida | Gerar com openssl rand -base64 48 e pôr em YAMTRACK_SECRET |
| Plex não mostra o menu de Webhooks | Recurso exclusivo de Plex Pass | Usar o rastreamento pelo Jellyfin. Ver Parte 12.2.3 |
Container sobe e morre com EACCES |
Pasta em /srv criada como root |
sudo chown -R 1000:1000 /srv/<serviço> |
| Filme importado some da pasta e o torrent para | Clean Library Level em Remove and Delete |
Radarr → Lists → Options → revisar a opção |
| Plex não aparece na conta | Falta o claim token | Gerar em plex.tv/claim e redeployar em até 4 minutos |
- Seedar é o preço da entrada. O qBittorrent continua semeando depois que o Radarr importa, porque o hardlink mantém o arquivo original vivo. Apagar do qBittorrent apaga uma das duas referências, e a mídia continua na biblioteca.
- Espaço em disco. A pasta
Downloadscresce sem parar. Hoje ela ocupa mais que a biblioteca inteira nesta instalação. Defina uma regra de seed (razão ou tempo) no qBittorrent para os torrents se auto-removerem. - Uma raiz por tipo de conteúdo. Cada pasta raiz extra é uma chance de mídia acabar em lugar errado e sumir do player.
- FlareSolverr é pesado. Ele sobe um Chrome headless a cada desafio. Numa placa ARM com 8 GB, use apenas nos indexadores que realmente precisam.
- A porta 8191 não vai para a internet. O FlareSolverr não tem autenticação nenhuma.
- Plex e Jellyfin podem conviver. Eles apenas leem as mesmas pastas. Não há conflito, só uso a mais de RAM e de CPU nas varreduras. Se for migrar de vez, mantenha os dois por um tempo até confirmar que os apps das TVs atendem bem o Jellyfin.
| Serviço | URL local | Portainer |
|---|---|---|
| qBittorrent | http://192.168.x.x:8080 |
Stack midia |
| Prowlarr | http://192.168.x.x:9696 |
Stack midia |
| Radarr | http://192.168.x.x:7878 |
Stack midia |
| Sonarr | http://192.168.x.x:8989 |
Stack midia |
| Bazarr | http://192.168.x.x:6767 |
Stack midia |
| Seerr | http://192.168.x.x:5055 |
Stack midia |
| Plex | http://192.168.x.x:32400/web |
Stack midia |
| Jellyfin | http://192.168.x.x:8096 |
Stack midia |
| Tautulli | http://192.168.x.x:8181 |
Stack midia |
| Yamtrack | http://192.168.x.x:8010 |
Stack midia |
| FileBot | http://192.168.x.x:5800 |
Stack midia |
- Meu "Netflix Pessoal" com Docker Compose, AkitaOnRails
- Guia do Streaming Doméstico Automatizado, r/pirataria
- TRaSH Guides: Hardlinks and Instant Moves
- TRaSH Guides: Radarr custom formats
- TRaSH Guides: qBittorrent Basic Setup
- Recyclarr, sincroniza o TRaSH Guides automaticamente
- nyanmisaka/jellyfin, imagem com RKMPP para Rockchip
- Jellyfin: Hardware Acceleration
- Plex: Using Hardware-Accelerated Streaming
- Seerr (fork do Overseerr)
- Yamtrack, rastreador de mídia self-hosted
- Yamtrack: variáveis de ambiente
- Jellyfin: plugin Webhook
- PlexTraktSync #2548: o Trakt exigindo VIP para apps OAuth