[PYTHON] Extract the lyrics information in the MP3 / MP4 file and save it in the lyrics file (* .lrc) for Sony walkman.

Background

I switched from an iPod to a Sony walkman a few years ago. The lyrics can be displayed on the walkman, and by entering the time information on each line of the lyrics, it scrolls according to the song or English conversation. It is very convenient for practicing singing and learning English conversation. However, the lyrics in the MP3 / MP4 file are not displayed, and the lyrics text must be saved in the LRC file dedicated to the lyrics.

Previously, with the software "Media Go" provided by Sony, you can play songs saved in iTunes for iPod, transfer them to the walkman, and open the properties of each song in iTunes and copy the lyrics text. Then I pasted it on the Media Go side and edited the lyrics time. This transfer work became tedious, and I made a Python script to extract the lyrics text from the MP3 / MP4 file and save it in the LRC file. You can simply display the lyrics, or specify the directory to create LRC files for all files at once.

Operating environment

Requires Python3 and mutagen modules. I'm using it in a Windows environment, Japanese songs have many Japanese filenames, and I needed Python3 to handle Japanese well. I also have the mutagen module installed and used with pip to read lyrics information from MP3 / MP4.

Installation of mutagen module

$ pip3 install mutagen
Or
$ python3 -m pip install mutagen
Or
$ sudo python3 -m pip install mutagen

How to use

Help display (help)

$ lyrics.py -h
usage: lyrics.py [-h] [-l] [-s] [-c] [-r] file [file ...]

positional arguments:
  file           file or directory name

optional arguments:
  -h, --help     show this help message and exit
  -l, --list     show file names containing lyrics (default)
  -s, --show     show lyrics
  -c, --create   create "*.lrc" lyrics files if it does not exist
  -r, --replace  create or replace "*.lrc" lyrics files

List of file names including lyrics information (list)

$ lyrics.py -l .

Show lyrics

$ lyrics.py -s "1-01 Just The Way You Are.mp3"
$ lyrics.py -s "Billy Joel"

Save to LRC file (create: only if it does not exist)

$ lyrics.py -c "Billy Joel"

Save to LRC file (replace: overwrite if it exists, note that time information will be lost)

$ lyrics.py -r "Billy Joel"

Source code

github

https://github.com/shiracamus/lyrics_converter

Python script

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
#
# Lyrics converter
#
# version: 2017.4.18
# author: @shiracamus
# github: https://github.com/shiracamus/lyrics_converter
#
# Need to install mutagen module
#     $ python3 -m pip install mutagen
# or
#     $ sudo python3 -m pip install mutagen
#

import os
import sys
import argparse
from mutagen.id3 import ID3, ID3NoHeaderError
from mutagen.mp4 import MP4, MP4StreamInfoError


def read_lyrics_in_mp3(path):
    try:
        tags = ID3(path)
        for key in tags:
            if key.startswith('USLT'):
                return tags[key].text
    except ID3NoHeaderError:
        pass
    return None


def read_lyrics_in_mp4(path):
    try:
        tags = MP4(path).tags
        if '\xa9lyr' in tags:
            return tags['\xa9lyr'][0]
    except MP4StreamInfoError:
        pass
    return None


def read_lyrics(path):
    return (read_lyrics_in_mp3(path) or
            read_lyrics_in_mp4(path) or
            None)


class Lyrics:

    def __init__(self, path):
        self.path = path
        self.path_base, self.path_ext = os.path.splitext(path)
        self.text = read_lyrics(path)
        self.exists = bool(self.text)

    def __repr__(self):
        return '<base="%s", ext="%s", lyrics=%s>' % (self.path_base,
                                                     self.path_ext,
                                                     self.exists)


class LRC:
    ext = '.lrc'

    def __init__(self, path):
        self.path = path
        self.exists = os.path.exists(self.path)

    def save(self, text):
        with open(self.path, 'w') as f:
            f.write(text)
        self.exists = True


def show_filename(lyrics):
    print(lyrics.path)


def show_lyrics(lyrics):
    print('=' * 30)
    print(lyrics.path)
    print('-' * 30)
    print(lyrics.text)
    print()


def save_lrc(lyrics, replace=False):
    lrc = LRC(lyrics.path_base + LRC.ext)
    if not lrc.exists or replace:
        lrc.save(lyrics.text)
        print('Saved "%s"' % lrc.path)
    else:
        print('Already exists "%s"' % lrc.path)


def pathes(files_and_directories):
    for file_or_directory in files_and_directories:
        if os.path.isfile(file_or_directory):
            yield file_or_directory
        elif os.path.isdir(file_or_directory):
            for root, dirs, files in os.walk(file_or_directory):
                for filename in files:
                    yield os.path.join(root, filename)


def parse_args():
    p = argparse.ArgumentParser()
    p.add_argument('-l', '--list', action='store_true',
                   help='show file names containing lyrics (default)')
    p.add_argument('-s', '--show', action='store_true',
                   help='show lyrics')
    p.add_argument('-c', '--create', action='store_true',
                   help='create "*.lrc" lyrics files if it does not exist')
    p.add_argument('-r', '--replace', action='store_true',
                   help='create or replace "*.lrc" lyrics files')
    p.add_argument('file', nargs='+', default='.',
                   help='file or directory name')
    args = p.parse_args()
    if not (args.show or args.create or args.replace):
        args.list = True
    return args


def main(args):
    for path in pathes(args.file):
        lyrics = Lyrics(path)
        if not lyrics.text:
            continue
        if args.list:
            show_filename(lyrics)
        if args.show:
            show_lyrics(lyrics)
        if args.create or args.replace:
            save_lrc(lyrics, replace=args.replace)

if __name__ == '__main__':
    main(parse_args())

from now on

In-source comments will be added sequentially. I want to be able to handle other than MP3 / MP4, so please let me know if you know the processing method. I also want to make a GUI wrapper. It would be great if time information could be created automatically, but there is still no library that recognizes voice from songs and creates lyrics, right?

Recommended Posts

Extract the lyrics information in the MP3 / MP4 file and save it in the lyrics file (* .lrc) for Sony walkman.
How to save the feature point information of an image in a file and use it for matching
Read the csv file and display it in the browser
Save the pystan model and results in a pickle file
Save the binary file in Python
The one that divides the csv file, reads it, and processes it in parallel
Extract information using File :: Stat in Ruby
Find it in the procession and edit it
Save the specified channel ID in text and load it at the next startup
Extract only the file name excluding the directory in the directory
12. Save the first column in col1.txt and the second column in col2.txt
In bash, "Delete the file if it exists".
I want to replace the variables in the python template file and mass-produce it in another file.
Extract and list personal names and place names in the text
Select the required variables in TensorFlow and save / restore
Extract only the sound of a specific instrument from a MIDI file and make it a separate file
Parse the Researchmap API in Python and automatically create a Word file for the achievement list