Use metaflac to rename .flac files from flac tags recursively
Solution 1
I have found a python script written by Louis-Philippe Véronneau.
The up to date code can be found on his git repository: https://gitlab.com/baldurmen/rename-flac
You need to install python-docopt (sudo apt-get install python-docopt) and run this script after you chmod +x rename-flac.py it:
#!/usr/bin/python
"""
rename-flac takes the information from FLAC metadata to batch rename
the files according to a filenaming scheme.
Usage:
rename-flac.py [--verbose] <scheme> <directory>
rename-flac.py (-h | --help)
rename-flac.py --version
Arguments:
<scheme> The filenaming scheme. Has to be between quotation marks
<directory> The path to the directory containing the album
Options:
-h --help Shows the help screen
--version Outputs version information
--verbose Runs the program as verbose mode
These are the options you can use to define the filenaming scheme:
%a = Artist | %b = Album | %d = Date
%g = Genre | %n = Tracknumber | %t = Title
"""
import sys
try:
from docopt import docopt # Creating command-line interface
except ImportError:
sys.stderr.write("""
%s is not installed: this program won't run correctly.
To install %s, run: aptitude install %s
""" % ("python-docopt", "python-docopt", "python-docopt"))
import subprocess
import re
import os
TAGS = dict(a='artist', b='album', d='date',
g='genre', n='tracknumber', t='title')
# Defining the function that fetches metadata and formats it
def metadata(filepath):
args = ["--show-tag=%s" % tag for tag in TAGS.values()]
tags = ["%s=" % tag for tag in TAGS.values()]
formatter = dict()
pipe = subprocess.Popen(["metaflac"] + args + [filepath],
stdout=subprocess.PIPE)
output, error = pipe.communicate()
if pipe.returncode:
raise IOError("metaflac failed: %s" % error)
output = output.splitlines()
for tag in tags:
for item in output:
x = re.compile(re.escape(tag), re.IGNORECASE)
if bool(re.match(x, item)) == True:
tag = tag.replace("=", "")
if tag == "tracknumber":
formatter[tag] = x.sub("", item).zfill(2)
else:
formatter[tag] = x.sub("", item)
return formatter
# Defining function that renames the files
def rename(scheme, dirname, filename, args):
filepath = os.path.join(dirname, filename)
new_filename = scheme % metadata(filepath) + ".flac"
if new_filename == filename:
if args["--verbose"] == True:
print("%s is already named correctly") % (filename)
else:
new_filepath = os.path.join(dirname, new_filename)
os.rename(filepath, new_filepath)
if args["--verbose"] == True:
print("%s >> %s") % (filename, new_filename)
# Defining main function
def main():
args = docopt(__doc__, version="rename-flac 1.0")
scheme = args["<scheme>"]
if not re.search("%[tn]", scheme): # To have a unique filename
sys.stderr.write("%t or %n has to be present in <scheme>\n")
return
scheme = re.sub('%%([%s])' % ''.join(TAGS.keys()),
lambda m: '%%(%s)s' % TAGS[m.group(1)],
scheme)
for dirname, _, filenames in os.walk(
args["<directory>"],
topdown=False):
for filename in filenames:
if os.path.splitext(filename)[1] == ".flac":
try:
rename(scheme, dirname, filename, args)
except KeyboardInterrupt:
raise
except OSError:
print("Song title contains /. Please rename it")
# Calling main function
if __name__ == "__main__":
main()
I tested it and everything works like a charm! Thank you!
Solution 2
If you put your code into its own file, make it executable, and place in your binary path (e.g. ~/bin).
e.g. rename_flac_tracks_from_meta.sh
You could then use find and xargs to recursively go through your directories and apply your script to each one.
$ cd path/to/flac/folders
$ find . -type d -print0 | xargs -0 -t -I{} sh -c 'cd "{}" && rename_flac_tracks_from_meta.sh'
Bear in mind that will crawl into directories that might not have flacs in, but it should just hiccup rather than die.
Related videos on Youtube
BlackR
Updated on September 18, 2022Comments
-
BlackR over 1 year
I am trying to rename a bunch of songs using metaflac (sudo apt-get install flac) from their respective tags recursively, because I'm dealing with an unknown number of subfolders.
Output should be: $TRACKNUMBER. $TITLE.flac
This is my attempt, however it does not work recursively:
for a in *.flac; do TITLE=`metaflac "$a" --show-tag=TITLE | sed s/.*=//g` TRACKNUMBER=`metaflac "$a" --show-tag=TRACKNUMBER | sed s/.*=//g` mv "$a" "`printf %02g $TRACKNUMBER`. $TITLE.flac"; done
I do not know why, but sometimes I get "The FLAC file could not be opened. Most likely the file does not exist or is not readable. *.flac: ERROR: reading metadata, status = "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE"".
Is there a better way to do it in a recursive manner? I also prefer oneliners. Thanks in advance!
-
Amir Uval almost 8 yearsI got this error only in file names that contained spaces
-