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.101 ]
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
Verificar status de carga da bateria do notebook
Eu vejo gente morta. Descubra se alguém já morreu!
Enviar mensagem ao usuário trabalhando com as opções do php.ini
Meu Fork do Plugin de Integração do CVS para o KDevelop
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Compartilhamento de Rede com samba em modo Público/Anônimo de forma simples, rápido e fácil
Cups: Mapear/listar todas as impressoras de outro Servidor CUPS de forma rápida e fácil
Criando uma VPC na AWS via CLI
Tem como instalar o gerenciador AMD Adrenalin no Ubuntu 24.04? (9)