tag-mp3 - Um script para editar e/ou visualizar algumas tags ID3 de arquivos MP3
Publicado por João Gabriel (última atualização em 23/12/2021)
[ Hits: 2.524 ]
tag-mp3 é um script para editar e/ou visualizar algumas tags ID3 de arquivos MP3.
Esse script suporta adição e remoção de imagens para a capa e o verso do álbum.
Eu fiz esse script para uso pessoal, por isso não estão presentes tags ID3 que não uso.
Os requerimentos são bash, ffmpeg e GNU getopt (o script funciona sem o GNU getopt se as linhas 158 - 160 forem removidas, porém com funcionalidade diferente em relação a forma de tratar as opções).
#!/usr/bin/env bash
## Script para alterar e / ou listar metadados de arquivos MP3
## v1 - por goll72
edit() {
[ "$opt_list" ] || printf '\nArquivo: %s\n\n' "$1"
printf "\nSe você quiser manter um item no seu valor original, pressione Enter. Se você quiser remover um item, digite '/rm'.\n"
printf "PS: Digitar '/rm' em um dos campos 'Imagem do álbum' removerá TODAS as streams de vídeo do arquivo.\n\n"
read -erp 'Título: ' ans_title
read -erp 'Subtítulo: ' ans_subtitle
read -erp 'Álbum: ' ans_album
read -erp 'Artista: ' ans_artist
read -erp 'Artista do Álbum: ' ans_alb_artist
read -erp 'Comentário: ' ans_comment
read -erp 'Ano: ' ans_year
until [ -z "$ans_year" ] || [[ "$ans_year" == '/rm' ]] || date +%Y -d "$ans_year-1-1" &>/dev/null; do
printf 'Ano inválido.\n'
read -erp 'Ano: ' ans_year
done
read -erp 'Gênero: ' ans_genre
read -erp 'Nº Faixa: ' ans_track
# É preciso verificar se o arquivo de imagem é válido
read -erp "Imagem da capa do álbum (ex. $HOME/album.jpg) : " ans_alb_img_front
until [ -z "$ans_alb_img_front" ] || [[ "$ans_alb_img_front" == '/rm' ]] || file -b --mime-type -- "$ans_alb_img_front" | grep 'image' &>/dev/null ; do
printf '%s: arquivo inválido!\n' "$ans_alb_img_front"
read -erp "Imagem da capa do álbum (ex. $HOME/album.jpg) : " ans_alb_img_front
done
read -erp "Imagem do verso do álbum (ex. $HOME/album-verso.jpg) : " ans_alb_img_back
until [ -z "$ans_alb_img_back" ] || [[ "$ans_alb_img_back" == '/rm' ]] || file -b --mime-type -- "$ans_alb_img_back" | grep 'image' &>/dev/null ; do
printf '%s: arquivo inválido!\n' "$ans_alb_img_back"
read -erp "Imagem do verso do álbum (ex. $HOME/album-verso.jpg) : " ans_alb_img_back
done
printf '\n'
# shellcheck disable=SC2191 disable=SC2206
build_ffmpeg_opts() {
if [[ "$1" == '/rm' ]]; then
ffmpeg_opts+=(-metadata $2="")
elif [ "$1" ]; then
ffmpeg_opts+=(-metadata $2="$1")
fi
}
# Monta a lista de argumentos do ffmpeg baseado nas respostas do usuário
build_ffmpeg_opts "$ans_title" 'title'
build_ffmpeg_opts "$ans_subtitle" 'TIT3'
build_ffmpeg_opts "$ans_album" 'album'
build_ffmpeg_opts "$ans_artist" 'artist'
build_ffmpeg_opts "$ans_alb_artist" 'album_artist'
build_ffmpeg_opts "$ans_comment" 'comment'
build_ffmpeg_opts "$ans_year" 'date'
build_ffmpeg_opts "$ans_genre" 'genre'
build_ffmpeg_opts "$ans_track" 'track'
# Cria um arquivo temporário usado pelo ffmpeg
tempfile=$(mktemp -u --suffix '.mp3')
[ "${ffmpeg_opts[*]}" ] && {
printf 'Executando ffmpeg ...\n\n'
ffmpeg -hide_banner -i "$1" "${ffmpeg_opts[@]}" -c copy -id3v2_version 3 "$tempfile"
mv "$tempfile" "$1"
}
# TODO: Não remover todas as streams de vídeo do arquivo
if [[ "$ans_alb_img_front" == '/rm' ]] || [[ "$ans_alb_img_back" == '/rm' ]]; then
printf 'Removendo TODAS as streams de vídeo do arquivo ...\n'
ffmpeg -hide_banner -i "$1" -vn -c copy -id3v2_version 3 "$tempfile"
mv "$tempfile" "$1"
fi
# Adiciona a capa do álbum
[ "$ans_alb_img_front" ] && [[ "$ans_alb_img_front" != '/rm' ]] && {
printf 'Adicionando capa do álbum ...\n'
ffmpeg -hide_banner -i "$1" -i "$ans_alb_img_front" -map 0:0 -map 1:0 -c copy -id3v2_version 3 -metadata:s:v comment="Cover (front)" "$tempfile"
mv "$tempfile" "$1"
}
# Adiciona o verso do álbum
[ "$ans_alb_img_back" ] && [[ "$ans_alb_img_back" != '/rm' ]] && {
printf 'Adicionando verso do álbum ...\n'
ffmpeg -hide_banner -i "$1" -i "$ans_alb_img_back" -map 0:0 -map 1:0 -c copy -id3v2_version 3 -metadata:s:v comment="Cover (back)" "$tempfile"
mv "$tempfile" "$1"
}
[ "$opt_list" ] && { printf 'Após a modificação:\n'; list "$1"; }
}
list() {
printf '\nArquivo: %s\n\n' "$1"
# Caso essas variáveis não fossem locais, haveria um risco dos metadados do arquivo mudarem, porém o valor da variável se manter
local info title subtitle album artist alb_artist comment year genre track alb_front alb_back
info=$(ffprobe -hide_banner -of flat -show_streams -show_format "$1" 2>/dev/null)
title=$(grep -Po '^format\.tags\.title=\K".*?"$' <<< "$info"); title=${title:-'Sem título'}
subtitle=$(grep -Po '^format\.tags\.TIT3=\K".*?"$' <<< "$info"); subtitle=${subtitle:-'Sem subtítulo'}
album=$(grep -Po '^format\.tags\.album=\K".*?"$' <<< "$info"); album=${album:-'Sem álbum'}
artist=$(grep -Po '^format\.tags\.artist=\K".*?"$' <<< "$info"); artist=${artist:-'Sem artista'}
alb_artist=$(grep -Po '^format\.tags\.album_artist=\K".*?"$' <<< "$info"); alb_artist=${alb_artist:-'Sem artista do álbum'}
comment=$(grep -Po '^format\.tags\.comment=\K".*?"$' <<< "$info"); comment=${comment:-'Sem comentário'}
year=$(grep -Po '^format\.tags\.date=\K".*?"$' <<< "$info"); year=${year:-'Sem ano'}
genre=$(grep -Po '^format\.tags\.genre=\K".*?"$' <<< "$info"); genre=${genre:-'Sem gênero'}
track=$(grep -Po '^format\.tags\.track=\K".*?"$' <<< "$info"); track=${track:-'Sem nº faixa'}
# Descobre se há imagem do álbum ou não
# TODO: Utilizar um método mais robusto; esse método falha se houver uma stream de áudio no arquivo com o comentário "Cover (front)"
# ou "Cover (back)", pois assume que se houver uma stream com esse(s) comentário(s), será sempre uma stream de vídeo
grep -Po '^streams\.stream\.\d\.tags\.comment="Cover \(front\)"' <<< "$info" &>/dev/null && alb_front=1
grep -Po '^streams\.stream\.\d\.tags\.comment="Cover \(back\)"' <<< "$info" &>/dev/null && alb_back=1
[ -n "$alb_front" ] && [ -n "$alb_back" ] && alb_img='Sim (frente e verso) '
[ -n "$alb_front" ] && [ -z "$alb_back" ] && alb_img='Sim (frente) '
[ -z "$alb_front" ] && [ -n "$alb_back" ] && alb_img='Sim (verso) '
[ -z "$alb_front" ] && [ -z "$alb_back" ] && alb_img='Não '
# Formata o texto usando o column
{
printf 'Título: ^%s ^Subtítulo: ^%s ^Álbum: ^%s\n' "$title" "$subtitle" "$album"
printf 'Artista: ^%s ^Artista do Álbum: ^%s ^Comentário: ^%s\n' "$artist" "$alb_artist" "$comment"
printf 'Ano: ^%s ^Gênero: ^%s ^Faixa: ^%s\n' "$year" "$genre" "$track"
printf 'Há imagem de álbum: ^%s\n' "$alb_img"
} | column -t -s'^' -R 2,4,6,8
}
quit() {
rm "$tempfile" &>/dev/null
exit 0
}
[ $# -eq 0 ] && printf '%s: requer opção! Veja %s --help.' "$0" "$0"
# Obtêm as opções
opts=$(getopt -o hle -l help,list,edit -- "$@")
eval set -- "$opts"
while true; do
case "$1" in
-h | --help ) printf 'Uso: %s [OPÇÕES] [--] [ARQUIVOS] [...]\n' "$0"
printf ' -h, --help Mostra esse menu de ajuda.\n'
printf ' -l, --list Lista os metadados dos arquivos MP3.\n'
printf ' -e, --edit Edita os metadados dos arquivos MP3.\n'
exit 0
;;
-l | --list ) opt_list=1; shift ;;
-e | --edit ) opt_edit=1; shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
for i in "$@"; do
file -b --mime-type -- "$i" | grep 'audio/mpeg' &>/dev/null || { printf '%s: %s: não é um arquivo MP3 válido!' "$0" "$i"; exit; }
[ "$opt_list" ] && list "$i"
[ "$opt_edit" ] && edit "$i"
done
quit
Script instalador do obmenu-generator e configuração do openbox
Reduz ou aumenta o tamanho da imagem
Dependências de Emuladores e DosBox
Wallpaper aleatório para Fluxbox
Cirurgia para acelerar o openSUSE em HD externo via USB
Void Server como Domain Control
Modo Simples de Baixar e Usar o bash-completion
Monitorando o Preço do Bitcoin ou sua Cripto Favorita em Tempo Real com um Widget Flutuante
Como impedir exclusão de arquivos por outros usuários no (Linux)
Cirurgia no Linux Mint em HD Externo via USB
Anúncio do meu script de Pós-Instalação do Ubuntu
Duas Pasta Pessoal Aparecendo no Ubuntu 24.04.3 LTS (12)
Alguém pode me indicar um designer freelancer? [RESOLVIDO] (5)
Alguém executou um rm e quase mata a Pixar! (3)
Formas seguras de instalar Debian Sid (1)
Por que passar nas disciplinas da faculdade é ruim e ser reprovado é b... (6)









