1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

flacファイルをm4aにタグやカバー画像などすべて変換する(Python)

Posted at

ipadにflacを移行できなかったためpythonでm4aにする。
またflac-m4a変換だけはなくタグの情報等も編集する。
当方、初投稿、故にMarkdown記法適当です。見にくかったらすみません。

事前準備

ffmpegをPCにインストールする

上のサイトからダウソして、解凍。詳しいインストール方法は各自お調べください。
次にPythonのライブラリのpydubとmutagenをインストールする

pip install pydub
pip install mutagen

サンプルコード

encode.py
#-*- coding:utf-8 -*-
import time, os, re
from pydub import AudioSegment
AudioSegment.converter = "C:\\ffmpeg\\bin\\ffmpeg.exe"
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')

#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__ == '__main__':
    for name in name_list:
        info = tag(name, path_in=_in, path_out=_out)
        cover.embed(info, cover_file='divide.jpg')

質問や指摘や、効率のいいコードがあれば是非コメントをください。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?