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 ]

Download tag-mp3




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).

  



Esconder código-fonte

#!/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

Scripts recomendados

Verificar status de carga da bateria do notebook

Eu vejo gente morta. Descubra se alguém já morreu!

O Orbe de Ícaro

Conversor de músicas

Duelo das Cartas Mágicas


  

Comentários
[1] Comentário enviado por maurixnovatrento em 09/01/2022 - 11:40h


Muito bacana esse script. Quer fazer alguma coisa para vídeo e áudio, o melhor é ffmpeg mesmo.

___________________________________________________________
[code]Conhecimento não se Leva para o Túmulo.
https://github.com/mxnt10 [/code]


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts