Legendar vídeos em Ruby com ferramentas de código aberto
Adicionar legendas a vídeos melhora significativamente a acessibilidade, o engajamento do público e o SEO. Quem desenvolve em Ruby tem acesso a várias ferramentas poderosas de código aberto que simplificam a integração e a edição de legendas. Vamos ver como você pode aproveitar essas ferramentas de forma eficaz.
Por que as legendas são importantes
As legendas não beneficiam apenas espectadores com deficiência auditiva. Elas também melhoram a compreensão para quem não é falante nativo, reforçam o SEO ao tornar o conteúdo pesquisável e podem aumentar a retenção do público. Oferecer legendas está se tornando uma prática padrão para conteúdo inclusivo e acessível.
Ferramentas Ruby de código aberto para legendas
O Ruby oferece várias bibliotecas robustas para gerenciar legendas, principalmente por meio da integração com o poderoso framework multimídia FFmpeg ou da manipulação direta de arquivos de legenda:
- streamio-ffmpeg: um wrapper Ruby completo para o FFmpeg que permite diversas tarefas de processamento de vídeo, incluindo gravar legendas diretamente nos vídeos ou converter formatos de legenda.
- srt: uma gem dedicada a analisar, manipular e gerar arquivos de legenda SRT (SubRip Text), o formato de legenda mais comum.
Vamos aos exemplos práticos com essas ferramentas.
Adicionar legendas com o streamio-ffmpeg
A gem streamio-ffmpeg oferece uma interface Ruby prática para o FFmpeg, facilitando a
incorporação de legendas aos vídeos. Esse processo costuma ser chamado de “gravar” as legendas
(burn-in), ou seja, elas passam a fazer parte dos quadros do vídeo.
Use uma versão do Ruby com suporte ativo e uma build do FFmpeg com o filtro subtitles
da libass, o encoder libx264 e o FFprobe. Verifique o filtro com
ffmpeg -filters; ele não está incluído em todas as builds de pacote. Instale estas
versões testadas das gems:
gem install streamio-ffmpeg:3.0.2 srt:0.1.5
Salve esta implementação compartilhada como subtitle_tools.rb. Todos os exemplos abaixo a
reutilizam. O diretório temporário mantém o nome do arquivo de legenda fora da sintaxe de filtros do
FFmpeg e isola o comportamento de sobrescrita do wrapper das saídas existentes. A publicação usa um
hard link no sistema de arquivos de saída; esse sistema de arquivos precisa oferecer suporte a hard
links.
require 'streamio-ffmpeg'
require 'srt'
require 'tmpdir'
module SubtitleTools
def self.load_srt(path)
raise ArgumentError, 'Subtitle input must be a regular file' unless File.file?(path)
text = File.binread(path, 1024 * 1024 + 1)
raise ArgumentError, 'Subtitle input exceeds 1 MiB' if text.bytesize > 1024 * 1024
text.force_encoding(Encoding::UTF_8)
raise ArgumentError, 'Subtitles must be valid UTF-8' unless text.valid_encoding?
subtitles = SRT::File.parse(text)
if subtitles.lines.empty? || !subtitles.errors.empty?
raise ArgumentError, 'Invalid or empty SRT input'
end
unless subtitles.lines.all? { |line| line.start_time >= 0 && line.end_time > line.start_time }
raise ArgumentError, 'Invalid subtitle timing'
end
subtitles
end
def self.with_output(output_path, extension)
output = File.expand_path(output_path)
if File.exist?(output) || File.symlink?(output)
raise ArgumentError, 'Output must not exist'
end
Dir.mktmpdir('.subtitles-', File.dirname(output)) do |temporary|
candidate = File.join(temporary, "result#{extension}")
yield candidate, temporary
raise IOError, 'No nonempty output produced' unless File.file?(candidate) && File.size(candidate) > 0
File.link(candidate, output)
end
end
def self.burn(video_path, subtitle_path, output_path)
subtitles = load_srt(subtitle_path)
movie = FFMPEG::Movie.new(File.expand_path(video_path))
raise ArgumentError, 'Invalid video input' unless movie.valid?
with_output(output_path, '.mp4') do |_candidate, temporary|
File.write(File.join(temporary, 'captions.srt'), subtitles.to_s)
# Fixed basenames avoid FFmpeg's separate filter-path escaping rules.
Dir.chdir(temporary) do
movie.transcode('result.mp4', {
video_codec: 'libx264', audio_codec: 'aac',
custom: ['-nostdin', '-vf', 'subtitles=captions.srt', '-threads', '2']
})
end
end
end
def self.write_srt(subtitles, output_path)
with_output(output_path, '.srt') { |candidate| File.write(candidate, subtitles.to_s) }
end
def self.convert_to_vtt(subtitle_path, output_path)
subtitles = load_srt(subtitle_path)
with_output(output_path, '.vtt') do |candidate, temporary|
input = File.join(temporary, 'captions.srt')
File.write(input, subtitles.to_s)
unless system('ffmpeg', '-nostdin', '-n', '-i', input, '-c:s', 'webvtt', candidate)
raise IOError, 'Subtitle conversion failed'
end
end
end
end
Esta implementação é voltada para um worker de CLI sequencial: Dir.chdir afeta todo o
processo Ruby, então não a chame simultaneamente a partir de várias threads. Use processos separados
e isolados ao escalar. O FFmpeg e o parser ainda precisam ser executados com limites de recursos
para arquivos não confiáveis; nomes de arquivo seguros não transformam o processo em um sandbox de
processamento de mídia. O helper recodifica o vídeo e o áudio em MP4.
Use-o a partir de um script no mesmo diretório:
require_relative 'subtitle_tools'
SubtitleTools.burn('input.mp4', 'subtitles.srt', 'output_with_subs.mp4')
puts 'Subtitles added'
Manipular arquivos SRT com a gem SRT
A gem srt permite analisar, modificar e criar arquivos de legenda SRT de forma
programática. Isso é útil para tarefas como ajustar a sincronização, corrigir o texto ou gerar
legendas do zero.
require_relative 'subtitle_tools'
subtitles = SubtitleTools.load_srt('subtitles.srt')
subtitles.timeshift(all: '+2.5s')
SubtitleTools.write_srt(subtitles, 'modified.srt')
puts 'Subtitles shifted by 2.5 seconds'
O método timeshift da gem recebe um hash de opções, não um atraso numérico. O parser
dela pode registrar erros nas linhas de legenda em vez de lançar um SRT::Error
dedicado; o loader compartilhado verifica esses erros reportados e valida se as durações das
legendas são positivas antes do processamento.
Converter formatos de legenda
Embora a gem srt seja focada especificamente no formato SRT, você pode usar o
FFmpeg por meio da gem streamio-ffmpeg para converter entre vários formatos de legenda.
Isso é especialmente útil para players de vídeo web, que muitas vezes preferem o formato WebVTT.
require_relative 'subtitle_tools'
SubtitleTools.convert_to_vtt('subtitles.srt', 'subtitles.vtt')
puts 'WebVTT subtitles saved'
O helper executa o FFmpeg com argumentos separados, verifica o status de saída e publica apenas um resultado não vazio. Mantenha as escolhas de formato e extensão juntas ao adaptá-lo para outro codec.
Tratamento de erros na integração de legendas
Deixe as falhas do helper se propagarem até um único ponto de fronteira da CLI. Salve isto como
add_subtitles.rb ao lado de subtitle_tools.rb; o script retorna um status
diferente de zero sem expor erros brutos do decoder ou do documento.
require_relative 'subtitle_tools'
abort 'Usage: ruby add_subtitles.rb <video.mp4> <subtitles.srt> <new-output.mp4>' unless ARGV.length == 3
begin
SubtitleTools.burn(*ARGV)
puts 'Subtitles added'
rescue StandardError
warn 'Subtitle processing failed. Check the inputs, output path, and FFmpeg installation.'
exit 1
end
Execute ruby add_subtitles.rb input.mp4 subtitles.srt output_with_subs.mp4. Diagnósticos do decoder ainda podem aparecer em um log local do
FFmpeg; não envie esses logs diretamente para clientes web.
Formatos de legenda compatíveis
Ao trabalhar com legendas, especialmente com o FFmpeg, você pode se deparar com vários formatos. Os principais são:
- SRT (SubRip Text):
.srt- O formato de texto simples mais amplamente suportado. Tratado diretamente pela gemsrte pelo FFmpeg. - WebVTT (Web Video Text Tracks):
.vtt- O padrão para legendas de vídeo em HTML5, com suporte a estilização e posicionamento. O FFmpeg consegue converter de e para esse formato. - ASS/SSA (Advanced SubStation Alpha / SubStation Alpha):
.ass/.ssa- Formatos mais avançados, com suporte a estilização complexa, posicionamento e efeitos, muito usados em fansubs de anime. O FFmpeg oferece um bom suporte. - SBV (SubViewer):
.sbv- Um formato simples usado pelo YouTube. O FFmpeg consegue fazer a conversão.
O FFmpeg oferece amplo suporte para converter entre esses e outros formatos. A gem
srt é focada especificamente em analisar e manipular o formato SRT.
Exemplo prático: processar vídeos com legendas em lote
Veja um script que demonstra como processar vários vídeos em um diretório, adicionando as legendas SRT correspondentes quando encontradas.
require_relative 'subtitle_tools'
def batch_process_videos(video_dir, subtitle_dir, output_dir)
video_files = Dir.children(video_dir).sort.filter_map do |name|
path = File.join(video_dir, name)
path if File.extname(name).downcase == '.mp4' && File.file?(path) && !File.symlink?(path)
end
raise ArgumentError, 'No MP4 files found' if video_files.empty?
Dir.mkdir(output_dir, 0700)
failures = 0
video_files.each do |video|
basename = File.basename(video, File.extname(video))
begin
SubtitleTools.burn(video, File.join(subtitle_dir, "#{basename}.srt"),
File.join(output_dir, "#{basename}_subtitled.mp4"))
puts "Converted #{basename}"
rescue StandardError
failures += 1
warn "Conversion failed for #{basename}"
end
end
failures.zero? ? 0 : 1
end
abort 'Usage: ruby batch_subtitles.rb <videos> <subtitles> <new-output-directory>' unless ARGV.length == 3
begin
exit batch_process_videos(*ARGV)
rescue StandardError
warn 'Cannot prepare batch. Check input directories and use a new output directory.'
exit 1
end
Este script percorre os arquivos MP4 de um diretório especificado, procura um arquivo SRT
correspondente em outro diretório e usa SubtitleTools.burn para processar cada par, colocando
a saída em uma pasta designada. Salve-o como batch_subtitles.rb. Legendas ausentes ou
inválidas contam como falhas, mas o script ainda tenta processar os arquivos restantes. As saídas
concluídas são mantidas e os arquivos temporários parciais são removidos. O status de saída geral
indica se todas as conversões foram bem-sucedidas.
Conclusão
Adicionar legendas a vídeos com Ruby é simples com ferramentas de código aberto como a
streamio-ffmpeg (que se integra ao FFmpeg) e a gem srt. Essas
bibliotecas simplificam a gravação de legendas nos vídeos, a manipulação de arquivos SRT e a
conversão entre formatos, melhorando significativamente a acessibilidade dos seus vídeos e o
engajamento do público. Lembre-se de tratar possíveis erros de forma adequada para ter aplicações
robustas.
Para fluxos de trabalho de legendas mais complexos, processamento de vídeo em grande escala ou soluções baseadas em nuvem, considere um serviço dedicado. O Robot 🤖 /video/subtitle da Transloadit oferece recursos avançados de integração de legendas como parte do seu serviço de codificação de vídeo, lidando com vários formatos e estilos de forma eficiente.
