Como posso converter uma pasta de arquivos de áudio em um único arquivo (iterar em várias pastas)?

1

Eu tenho alguns jogos de rádio de várias séries. Alguns já são single-track, alguns são multi-track. Eu quero que tudo seja single-track. Eu não me importo de re-codificar; na verdade eu quero transferi-los para o meu dispositivo móvel e prefiro a saída opus.

De dentro de uma pasta de um único audiolivro, isso parece funcionar, convertendo o mp3 em opus:

ffmpeg -i "concat:$(ls *.mp3 | tr '\n' '|')" -acodec opus test.opus

Agora, eu realmente tenho vários programas de rádio em várias faixas que quero converter. Gostaria de definir uma função que eu possa usar com find ou canalizar os resultados de ls para.

Eu me atrapalhei com variantes disso:

function audioconcat { folder=$1; iformat=$2; oformat=$3; echo $folder; echo $iformat; echo $oformat; ffmpeg -i \'concat:$(find "$folder" -name *.$iformat | tr '\n' '|' | tr ' ' '\ ' | head -c -1)\' -acodec $oformat \'$folder.$oformat\'; }

Portanto, a idéia é procurar arquivos do formato de entrada fornecido dentro da pasta, entregá-los ao ffmpeg concatenate, codificar o fluxo para o formato de saída fornecido e salvá-lo como um único arquivo, usando o nome da pasta.

No entanto, sempre pareço ter problemas com espaços em branco e / ou minhas chamadas de funções aninhadas.

O que posso fazer para corrigir minha função? Alternativamente, qual método melhor existe para fazer a conversão conforme descrito acima?

    
por PiHalbe 26.02.2018 / 07:58

1 resposta

3

Você demonstrou vários antipadrões no seu código que poderiam ser melhorados. Veja Por que você não deve analisar a saída de ls (1) . Você não precisa analisar a saída do comando ls e evitar o uso de várias linhas de canal do shell com o comando tr e find .

Recomenda-se melhor usar as opções glob fornecidas pelo shell nativo, que no seu caso deve ser o bash shell.

O trecho de código $(ls *.mp3 | tr '\n' '|') poderia muito bem ser escrito em bash com as opções que ele fornece para globulação de arquivos como

shopt -s nullglob
mp3FileList=(*.mp3)

Esta opção de shell estendida é ativada para garantir que o resultado da glob vazia seja ignorado em vez de ser processado ao preencher na matriz. Você deve cd na pasta e fazer abaixo. Observe o | final após o array, já que você também o tinha originalmente na lista. Remova-o se não for necessário.

fileString=$( IFS='|'; echo "${mp3FileList[*]}|" )

Agora, a variável acima conteria a lista de arquivos em um formato | separado com um | no último, que pode então ser passado para o comando ffmpeg como

ffmpeg -i "concat:${fileString}" -acodec opus test.opus

Em relação ao seu segundo requisito para passar várias opções ao script. Você poderia estender este script para fazer

audioConcat() {
    (( "$#" < 3 )) && { printf 'insufficient arguments supplied' >&2; exit 1 ; }
    cd "$1" || { printf 'unable to navigate to target\n' >&2; exit 2 ; }

    shopt -q nullglob; nullglob_set=$?
    ((nullglob_set)) && shopt -s nullglob

    local fileList
    local fileString

    fileList=(*."${2}")

    if (( ${#fileList[@]} )); then
        fileString=$( IFS='|'; echo "${fileList[*]}" )
        ffmpeg -i "concat:${fileString}" -acodec "$3" "$1.$3"  
    else
        printf 'unable to find files of extension %s\n' "$2" >&2
        exit 3 
    fi

    ((nullglob_set)) && shopt -u nullglob      
}

Lembre-se de quando chamar a função, passe seus argumentos como

audioConcat '/path/to/mp3files/' 'mp3' 'opus'

É altamente recomendável que você comente a linha ffmpeg na função acima e veja se as variáveis são criadas como necessárias antes de chamar o comando real. Confirme também se você precisa do | na sua lista de arquivos.

Resumo rápido das construções usadas na função

  1. A opção nullglob definida durante a expansão do nome do caminho evitaria a expansão de um globo vazio, ou seja, quando nenhum arquivo .mp3 for encontrado, o array estaria vazio durante a expansão em vez de um glob não expandido
  2. $(IFS='|'; echo "${mp3FileList[*]}) é um truque para produzir para imprimir a saída no formato separado | . Estamos modificando o IFS em um sub-shell (o Input Field Separator) para que ele não seja modificado globalmente. A expansão de matriz com [*] concatenará a sequência com o conjunto de valores IFS .

Alguns misc. notas a serem consideradas: - Usar exit na função seria sair do shell atual em que você está executando a função. Pode não ser recomendado ao usar a partir da linha de comando e mais adequado quando executado a partir de um script com um conjunto de she-bang de intérprete adequado, caso em que sairia do sub-shell iniciado para executar o script. Se você planeja usar a partir da linha de comando com mais frequência, substitua as chamadas exit por return .

    
por 26.02.2018 / 08:49