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.102 ]
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
Zwifi - Conectar em rede Wi-Fi via terminal
Script para Conexão Automática com Internet a Rádio
Usar o Google Translate para ler (speak) a seleção
Script para "Ler" arquivos de texto
Calcular o consumo de energia elétrica de eletrodomésticos
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? (11)