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.621 ]

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

InstallDPKG reformulado - instalando pacotes DEB no Slackware

Configuração do repositório do Slackware Current

Comandos para Avira AntiVir (ATUALIZADO!)

Acertando número para numeração

Script para criação de diretorio do usuario no Samba com A.D.


  

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