Skip to content

Instantly share code, notes, and snippets.

@shiracamus
Created January 13, 2018 22:04
Show Gist options
  • Save shiracamus/26990525b0ef1a69aa813d4c3fea4eeb to your computer and use it in GitHub Desktop.
Save shiracamus/26990525b0ef1a69aa813d4c3fea4eeb to your computer and use it in GitHub Desktop.
convert lyrics data in mp3 files to lrc text files
#!/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())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment