Перекодирование m4a в flac, с помощью скрипта на python 3

Автор: Igor Kirsanov

Простая задача по перекодированию музыки из m4a в flac или mp3 встретилась с особенностями оболочки bash в ubuntu.

Для примера, название "-01 Test Of music.m4a", не будет обработано т.к. впереди идет знак минус "-", который не обрабатывается правильно без экранирования в bash скрипте. В самом названии так же могут встретиться управляющие конструкции. Задача вполне решаема, но гораздо удобнее использовать скрипт на python.

Особенности:

Для перекодирования используется утилита ffmpeg, и ее вызов через subprocess

Пример того как на BASH выглядит установка и перекодирование единичного файла с пробелами в названии.

sudo apt-get install ffmpeg
ffmpeg -i "01 Test Of music.m4a" -f flac "01 Test Of music.ffmpeg.flac"

Скрипт полностью рабочий, выполняет полностью задачу, но далек от идеала. Примечания смотрите в коде и ниже в пояснениях.

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import os
import subprocess


class cd:
    """Context manager for changing the current working directory"""
    def __init__(self, newPath):
        self.newPath = os.path.expanduser(newPath)

    def __enter__(self):
        self.savedPath = os.getcwd()
        os.chdir(self.newPath)

    def __exit__(self, etype, value, traceback):
        os.chdir(self.savedPath)


# !!!! обратить внимание на путь, прописан жестко для пользователя user в ubuntu
for root, dirs, files in os.walk("/home/user/Музыка/"):
    for file in files:
        if file.endswith(".m4a"):
            print("Путь к файлу  " + os.path.join(root, file))

            # command = "/usr/bin/ffmpeg -i '" + file + "' -f flac '" + file + ".flac'"
            command = ['ffmpeg']
            command.append('-i')
            command.append(file)
            command.append('-f')
            command.append('flac')
            command.append(file + '.flac')

            with cd(root):
                print (command)
                subprocess.call(command)
            print("======================================================================")

Пояснения:

  1. Менеджер контекста cd для subprocess можно было заменить на параметр cwd при вызове функции, но при разработке были ошибки, поэтому был использован работающий код из другого проекта. os.chdir(root) - сменит директорию для родительского проекта, для дочернего subprocess работать не будет.
  2. subrocess работает в режиме псевдо эмуляции терминала, где все изначально экранировано, поэтому дополнительно делать ничего не нужно, но если очень нужно, то можно использовать аргумент функции shell=True. Получаем полностью все возможности и недостатки
  3. os.walk("/home/user/Музыка/") - прописан жестко, т.к. не требовалась универсальность, нужен был только быстрый результат. Заменить на своё
  4. ffmpeg универсальный конвертер, если нужен другой формат, достаточно заменить -f flac на -f mp3. Входной файл не имеет большой роли, если его можно перекодировать через ffmpeg, ограничения заданы при поиске в скрипте file.endswith(".m4a")
  5. subprocess принимает на вход список, в простом варианте для строке bash достаточно было бы применить split по пробелу, но проблема в том, что наш файл может содержать пробел, поэтому быстрее составить список вручную через command.append().
  6. Название файла (file + '.flac') сделано по нескольким причинам, основная - удобство проверки, все ли прошло успешно, т.к. оригинал не удаляется скриптом. В последующем с помощью find удаляются оригиналы m4a, которые больше не нужны

Если файл flac уже есть в директории, рядом с файлом m4a, то ffmpeg спрашивает что делать дальше, необходимо произвести выбор, иначе скрипт дальше работать не будет

Кроме ffmpeg, так же есть хорошая утилита avconv, форк-клон ffmpeg, но в данном случае она будет использовать теже способы, что и ffmpeg для перекодирования, поэтому использую оригинал

# пример установки и конвертирования через avconv
sudo aptitude install libav-tools
avconv -i "-01 Test Of music.m4a" -f flac "-01 Test Of music.avconv.flac"