Support FLAC output format (#259)

* Convert to .flac option

* Embed metadata to FLAC

* Update usage help

* Write tests
This commit is contained in:
Ritiek Malhotra
2018-04-02 00:47:31 +05:30
committed by GitHub
parent 7f7c3d6f58
commit 96ab547c5c
8 changed files with 123 additions and 79 deletions

View File

@@ -1,8 +1,33 @@
import logzero
_log_format = ("%(color)s%(levelname)s:%(end_color)s %(message)s")
formatter = logzero.LogFormatter(fmt=_log_format)
_formatter = logzero.LogFormatter(fmt=_log_format)
# options
log = logzero.setup_logger(formatter=formatter)
log = logzero.setup_logger(formatter=_formatter)
args = None
# Apple has specific tags - see mutagen docs -
# http://mutagen.readthedocs.io/en/latest/api/mp4.html
M4A_TAG_PRESET = { 'album' : '\xa9alb',
'artist' : '\xa9ART',
'date' : '\xa9day',
'title' : '\xa9nam',
'year' : '\xa9day',
'originaldate' : 'purd',
'comment' : '\xa9cmt',
'group' : '\xa9grp',
'writer' : '\xa9wrt',
'genre' : '\xa9gen',
'tracknumber' : 'trkn',
'albumartist' : 'aART',
'discnumber' : 'disk',
'cpil' : 'cpil',
'albumart' : 'covr',
'copyright' : 'cprt',
'tempo' : 'tmpo',
'lyrics' : '\xa9lyr' }
TAG_PRESET = {}
for key in M4A_TAG_PRESET.keys():
TAG_PRESET[key] = key

View File

@@ -17,16 +17,16 @@ https://trac.ffmpeg.org/wiki/Encode/AAC
def song(input_song, output_song, folder, avconv=False):
""" Do the audio format conversion. """
if not input_song == output_song:
convert = Converter(input_song, output_song, folder)
log.info('Converting {0} to {1}'.format(
input_song, output_song.split('.')[-1]))
if avconv:
exit_code = convert.with_avconv()
else:
exit_code = convert.with_ffmpeg()
return exit_code
return 0
if input_song == output_song:
return 0
convert = Converter(input_song, output_song, folder)
log.info('Converting {0} to {1}'.format(
input_song, output_song.split('.')[-1]))
if avconv:
exit_code = convert.with_avconv()
else:
exit_code = convert.with_ffmpeg()
return exit_code
class Converter:
@@ -56,6 +56,8 @@ class Converter:
_, input_ext = os.path.splitext(self.input_file)
_, output_ext = os.path.splitext(self.output_file)
ffmpeg_params = ''
if input_ext == '.m4a':
if output_ext == '.mp3':
ffmpeg_params = '-codec:v copy -codec:a libmp3lame -ar 44100 '
@@ -68,6 +70,9 @@ class Converter:
elif output_ext == '.m4a':
ffmpeg_params = '-cutoff 20000 -codec:a libfdk_aac -ar 44100 '
if output_ext == '.flac':
ffmpeg_params = '-codec:a flac -ar 44100 '
# add common params for any of the above combination
ffmpeg_params += '-b:a 192k -vn '
ffmpeg_pre += ' -i'

View File

@@ -122,10 +122,11 @@ def get_arguments(raw_args=None, to_group=True, to_merge=True):
choices={'prompt', 'force', 'skip'})
parser.add_argument(
'-i', '--input-ext', default=config['input-ext'],
help='prefered input format .m4a or .webm (Opus)')
help='prefered input format .m4a or .webm (Opus)',
choices={'.m4a', '.webm'})
parser.add_argument(
'-o', '--output-ext', default=config['output-ext'],
help='prefered output extension .mp3 or .m4a (AAC)')
help='prefered output format .mp3, .m4a (AAC), .flac, etc.')
parser.add_argument(
'-ff', '--file-format', default=config['file-format'],
help='File format to save the downloaded song with, each tag '

View File

@@ -1,7 +1,8 @@
from mutagen.easyid3 import EasyID3
from mutagen.id3 import ID3, TORY, TYER, TPUB, APIC, USLT, COMM
from mutagen.mp4 import MP4, MP4Cover
from core.const import log
from mutagen.flac import Picture, FLAC
from core.const import log, TAG_PRESET, M4A_TAG_PRESET
import urllib.request
@@ -31,6 +32,9 @@ def embed(music_file, meta_tags):
elif music_file.endswith('.mp3'):
log.info('Applying metadata')
return embed.as_mp3()
elif music_file.endswith('.flac'):
log.info('Applying metadata')
return embed.as_flac()
else:
log.warning('Cannot embed metadata into given output extension')
return False
@@ -50,15 +54,7 @@ class EmbedMetadata:
# https://github.com/quodlibet/mutagen/blob/master/mutagen/easyid3.py
# Check out somewhere at end of above linked file
audiofile = EasyID3(music_file)
audiofile['artist'] = meta_tags['artists'][0]['name']
audiofile['albumartist'] = meta_tags['artists'][0]['name']
audiofile['album'] = meta_tags['album']['name']
audiofile['title'] = meta_tags['name']
audiofile['tracknumber'] = [meta_tags['track_number'],
meta_tags['total_tracks']]
audiofile['discnumber'] = [meta_tags['disc_number'], 0]
audiofile['date'] = meta_tags['release_date']
audiofile['originaldate'] = meta_tags['release_date']
self._embed_basic_metadata(audiofile, preset=TAG_PRESET)
audiofile['media'] = meta_tags['type']
audiofile['author'] = meta_tags['artists'][0]['name']
audiofile['lyricist'] = meta_tags['artists'][0]['name']
@@ -68,10 +64,6 @@ class EmbedMetadata:
audiofile['length'] = str(meta_tags['duration'])
if meta_tags['publisher']:
audiofile['encodedby'] = meta_tags['publisher']
if meta_tags['genre']:
audiofile['genre'] = meta_tags['genre']
if meta_tags['copyright']:
audiofile['copyright'] = meta_tags['copyright']
if meta_tags['external_ids']['isrc']:
audiofile['isrc'] = meta_tags['external_ids']['isrc']
audiofile.save(v2_version=3)
@@ -101,48 +93,13 @@ class EmbedMetadata:
""" Embed metadata to M4A files. """
music_file = self.music_file
meta_tags = self.meta_tags
# Apple has specific tags - see mutagen docs -
# http://mutagen.readthedocs.io/en/latest/api/mp4.html
tags = { 'album' : '\xa9alb',
'artist' : '\xa9ART',
'date' : '\xa9day',
'title' : '\xa9nam',
'year' : '\xa9day',
'originaldate' : 'purd',
'comment' : '\xa9cmt',
'group' : '\xa9grp',
'writer' : '\xa9wrt',
'genre' : '\xa9gen',
'tracknumber' : 'trkn',
'albumartist' : 'aART',
'disknumber' : 'disk',
'cpil' : 'cpil',
'albumart' : 'covr',
'copyright' : 'cprt',
'tempo' : 'tmpo',
'lyrics' : '\xa9lyr' }
audiofile = MP4(music_file)
audiofile[tags['artist']] = meta_tags['artists'][0]['name']
audiofile[tags['albumartist']] = meta_tags['artists'][0]['name']
audiofile[tags['album']] = meta_tags['album']['name']
audiofile[tags['title']] = meta_tags['name']
audiofile[tags['tracknumber']] = [(meta_tags['track_number'],
meta_tags['total_tracks'])]
audiofile[tags['disknumber']] = [(meta_tags['disc_number'], 0)]
audiofile[tags['date']] = meta_tags['release_date']
audiofile[tags['year']] = meta_tags['year']
audiofile[tags['originaldate']] = meta_tags['release_date']
audiofile[tags['comment']] = meta_tags['external_urls']['spotify']
if meta_tags['genre']:
audiofile[tags['genre']] = meta_tags['genre']
if meta_tags['copyright']:
audiofile[tags['copyright']] = meta_tags['copyright']
if meta_tags['lyrics']:
audiofile[tags['lyrics']] = meta_tags['lyrics']
self._embed_basic_metadata(audiofile, preset=M4A_TAG_PRESET)
audiofile[M4A_TAG_PRESET['year']] = meta_tags['year']
audiofile[M4A_TAG_PRESET['comment']] = meta_tags['external_urls']['spotify']
try:
albumart = urllib.request.urlopen(meta_tags['album']['images'][0]['url'])
audiofile[tags['albumart']] = [MP4Cover(
audiofile[M4A_TAG_PRESET['albumart']] = [MP4Cover(
albumart.read(), imageformat=MP4Cover.FORMAT_JPEG)]
albumart.close()
except IndexError:
@@ -150,3 +107,47 @@ class EmbedMetadata:
audiofile.save()
return True
def as_flac(self):
music_file = self.music_file
meta_tags = self.meta_tags
audiofile = FLAC(music_file)
self._embed_basic_metadata(audiofile)
audiofile['year'] = meta_tags['year']
audiofile['comment'] = meta_tags['external_urls']['spotify']
image = Picture()
image.type = 3
image.desc = 'Cover'
image.mime = 'image/jpeg'
albumart = urllib.request.urlopen(meta_tags['album']['images'][0]['url'])
image.data = albumart.read()
albumart.close()
audiofile.add_picture(image)
audiofile.save()
return True
def _embed_basic_metadata(self, audiofile, preset=TAG_PRESET):
meta_tags = self.meta_tags
audiofile[preset['artist']] = meta_tags['artists'][0]['name']
audiofile[preset['albumartist']] = meta_tags['artists'][0]['name']
audiofile[preset['album']] = meta_tags['album']['name']
audiofile[preset['title']] = meta_tags['name']
audiofile[preset['date']] = meta_tags['release_date']
audiofile[preset['originaldate']] = meta_tags['release_date']
if meta_tags['genre']:
audiofile[preset['genre']] = meta_tags['genre']
if meta_tags['copyright']:
audiofile[preset['copyright']] = meta_tags['copyright']
if meta_tags['lyrics']:
audiofile[preset['lyrics']] = meta_tags['lyrics']
if self.music_file.endswith('.flac'):
audiofile[preset['discnumber']] = str(meta_tags['disc_number'])
else:
audiofile[preset['discnumber']] = [(meta_tags['disc_number'], 0)]
if self.music_file.endswith('.flac'):
audiofile[preset['tracknumber']] = str(meta_tags['track_number'])
else:
audiofile[preset['tracknumber']] = [(meta_tags['track_number'],
meta_tags['total_tracks'])]