flacファイルをm4aにタグなどすべて変換したい(Python)

ipadで音楽を聴く際、flacファイルを利用できないことがあったのでそれを根本的に解決しようということでpythonを使用してコードを書いてみました。

ちなみに変換先のファイルはmp3にすることをおすすめします。m4aは情報量が少なすぎて大変でした。

 参考程度にどうぞ、解説が欲しい人はコメントで。hatenablogでうまくコードを乗せる方法がわからなかったのでqiitaにも上げときます。

qiita.com

#-*- coding:utf-8 -*-
import time, os, re
from pydub import AudioSegment
AudioSegment.converter = "C:\\ffmpeg\\bin\\ffmpeg.exe"
import ffmpeg, mutagen
from mutagen.flac import FLAC, Picture
from mutagen.mp4 import MP4Tags, MP4, MP4Cover
from os import path
#flacのタグ名とm4aのタグ名に整合性を取る
def tag_flac_m4a(tag):
  match tag:
      case 'title':
          return "\xa9nam"
      case 'artist':
          return "\xa9ART"
        case 'albumartist':
            return 'aART'
        case 'tracknumber':
            return 'trkn'
        case 'date':
            return '\xa9day'
        case 'genre':
            return '\xa9gen'
        case 'album':
            return '\xa9alb'

class tag:
    def __init__(self, name, path_in, path_out=None):
        #インスタンス変数に値を入力
        self.name = name            #ファイル名を定義
        self.path_in = path_in      #元ファイルのディレクトリのパスを定義
        self.path_out = path_out    #出力ファイルのディレクトリのパスを
    #flacをm4a変換
    def convert_m4a(self, path_out=None):
        path_out=self.path_out if path_out is None else None    #出力フォルダが定義されていなかったらインスタンス変数から取り出す
        import_path = self.path_in + self.name + '.flac'
        Audiodata = AudioSegment.from_file(import_path, 'flac')         #flacファイルの読み込み
        #m4aへエクスポート(タグはすべて消去される)
        export_path = path_out + self.name + '.m4a'             #ファイルのパスを定義
        Audiodata.export(export_path, format='ipod', codec='aac', bitrate='320k')   #エンコード
        print(f'{self.name}のエクスポートが完了しました。')
    #タグを抽出
    def get(self):
        audio_info = FLAC(self.path_in + self.name + '.flac')
        tagname_list = ['title','artist','albumartist','date','tracknumber','genre','album']
        tag_dict = dict()
        #タグの情報を辞書に格納{tag:info}
        for tagname in tagname_list:
            try:
                tag_temp = {tagname:audio_info.tags[tagname]}
            except KeyError:
                continue
            tag_dict = {**tag_dict, **tag_temp}
        self.tag_dict = tag_dict
        print('タグの抽出を完了しました。')
        return tag_dict
  def embed(self, path_out=None):
        path_out=self.path_out if path_out is None else None
        self.get()
        #m4aのタグを初期化
        tags = MP4Tags()
        for k,v in self.tag_dict.items():
            tagname = tag_flac_m4a(k)
            #トラック番号の場合 入力方法が異なる
            if tagname == 'trkn':
                v = re.findall(r'[0-9]+', v[0])
                if len(v)==2:
                    tags[tagname] = [(int(v[0]), int(v[1]))]
                else:
                    tags[tagname] = [(int(v[0]), int(v[0]))]
                continue
            tags[tagname] = v[0]
        tags.save(path_out + self.name + '.m4a')
        print('タグの埋め込みを完了しました。')

#海外の方から拝借
class cover(tag):
    #画像をflacファイルから抽出
    # '  https://stackoverflow.com/questions/67394817/from-flac-file-get-cover-image-and-display-it-on-a-tkinter-window  '
    def get(self):
        audio_file = self.path_in + self.name + '.flac'
        flacObj = FLAC(audio_file)
        coverArt = flacObj.pictures
        for img in coverArt:
            if img.type == 3:
                with open(f'cover_file\\{self.name}.jpg', "wb") as f:
                    f.write(img.data)
                print(f"{self.name}_cover.jpg の保存を完了しました。")
    #画像をm4aファイルに埋め込む
    #' https://python.hotexamples.com/jp/site/file?hash=0xf3bcb50e83333b6591172b93a6b1089b4f05105494cf35ac8c56441d132c78dd&fullName=musicgen.py&project=nejsan/sound_bubble '
    def embed(self, cover_file=None):
        """Embeds cover art into an audio file.
        Arguments:
            audio_file (str): The path to the audio file to embed the artwork in.
            cover_file (str): The path to the artwork file to embed.
        """
        if cover_file is None:
            cover_file = f'cover_file\\{self.name}.jpg'
        audio_file = self.path_out + self.name + '.m4a'
        if path.isfile(audio_file) and path.isfile(cover_file):
            artwork = open(cover_file, "rb").read()
            # Determine which filetype we're handling
            if audio_file.endswith("m4a"):
                audio = MP4(audio_file)
                covr = []
                if cover_file.endswith("png"):
                    covr.append(MP4Cover(artwork, MP4Cover.FORMAT_PNG))
                else:
                    covr.append(MP4Cover(artwork, MP4Cover.FORMAT_JPEG))
                audio.tags["covr"] = covr
            audio.save()
            print(f'{self.name}のエクスポートを完全に完了しました。')
        else:
            with open('encoding.log', 'a', encoding='utf-8') as f:
                f.writelines('/cover:File is Not Found')
#
音声データをaacに変換
def convert_m4a(path, name_list, extension):
    for name in name_list:
        #ファイルのパスを設定
        dir = path + '\\' + name + extension
        #flacファイルの読み込み
        Audiodata = AudioSegment.from_file(dir, 'flac')
        #m4aへエクスポート(ID3タグはすべて消去される)
        Audiodata.export('music_file\\'+name+'.m4a', format='ipod', codec='aac', bitrate='320k')
#glob.globのほうがいいかも
#変換したい音楽ファイルのディレクト
_in = "Music\\"
_out = "C:\\Documents\\music_m4a\\"
#ファイルの名前をリストに落とす
file_list = os.listdir(path=_in)
#flac拡張子のファイル名を抽出
flac_list = [s for s in file_list if '.flac' in s]
#拡張子を削除した名前リスト
name_list = [re.sub('.flac', '', name) for name in flac_list]
with open('encoding.log', 'w', encoding='utf-8') as f:
    for name in name_list:
        f.writelines(name + '\n')
if __name__=='__main__':
    for name in name_list:
        info = tag(name, path_in=_in, path_out=_out)
        with open('encoding.log', 'a', encoding='utf-8') as f:
            f.writelines('\n'+info.name)
        info.convert_m4a()
        info.get()
        info.embed()
        cover.get(info)
        cover.embed(info)
name_list = ['Perfect', 'Shape Of You']
#カバーを埋め込むだけ
if __name__ == '':
    for name in name_list:
        info = tag(name, path_in=_in, path_out=_out)
        with open('encoding.log', 'a', encoding='utf-8') as f:
            f.writelines('\n'+info.name)
        cover.embed(info, cover_file='divide.jpg')

qiita.com

www.wizard-notes.com

www.wizard-notes.comt

programtalk.com

fossies.org参考サイト