2 changed files with 127 additions and 11 deletions
@ -0,0 +1,97 @@ |
|||
#!/usr/bin/env python3 |
|||
|
|||
# Normalisation is done at the default of each program, |
|||
# which is usually -89.0 dB |
|||
|
|||
import os |
|||
import subprocess |
|||
import coloredlogs |
|||
import logging |
|||
import progressbar |
|||
|
|||
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s') |
|||
log = logging.getLogger() |
|||
|
|||
|
|||
# Constants |
|||
FORCE = False # TODO UX cli argument |
|||
SOURCE_FOLDER = os.path.join(os.path.expanduser("~"), "Musique") |
|||
GAIN_COMMANDS = {("flac",): ["metaflac", "--add-replay-gain"], |
|||
("mp3",): ["mp3gain", "-a", "-k"] + (["-s", "r"] if FORCE else []), |
|||
("m4a", "mp4"): ["aacgain", "-a", "-k"] + (["-s", "r"] if FORCE else []), |
|||
("ogg",): ["vorbisgain", "--album"] + ([] if FORCE else ["--fast"]), |
|||
} |
|||
|
|||
# Since metaflac ALWAYS recalculate the tags, we need to specificaly verify |
|||
# that the tags are present on every track of an album to skip it |
|||
def isFlacTagged(f): |
|||
# TODO PERF Run metaflac --show-tag for the whole album and compare the |
|||
# output with the number of files tagged |
|||
for tag in ["REPLAYGAIN_TRACK_GAIN", "REPLAYGAIN_ALBUM_GAIN"]: |
|||
cmd = ["metaflac", "--show-tag", tag, f] |
|||
proc = subprocess.run(cmd, stdout=subprocess.PIPE) |
|||
res = len(proc.stdout.strip()) > 0 |
|||
if not res: |
|||
return False |
|||
return True |
|||
|
|||
# TODO UX Do the same thing with other formats so the output is not |
|||
# inconsistent |
|||
|
|||
# Get album paths |
|||
albums = set() |
|||
for root, dirs, files in os.walk(SOURCE_FOLDER): |
|||
|
|||
relRoot = os.path.relpath(root, SOURCE_FOLDER) |
|||
|
|||
# See if it's an album (only 2 components in the path) |
|||
head, tail = os.path.split(relRoot) |
|||
if not len(head): |
|||
continue |
|||
head, tail = os.path.split(head) |
|||
if len(head): |
|||
continue |
|||
albums.add(root) |
|||
|
|||
cmds = list() |
|||
for album in albums: |
|||
albumName = os.path.relpath(album, SOURCE_FOLDER) |
|||
log.info("Processing album {}".format(albumName)) |
|||
|
|||
musicFiles = dict() |
|||
for root, dirs, files in os.walk(album): |
|||
for f in files: |
|||
ext = os.path.splitext(f)[1][1:].lower() |
|||
|
|||
for exts in GAIN_COMMANDS.keys(): |
|||
if ext in exts: |
|||
if exts not in musicFiles.keys(): |
|||
musicFiles[exts] = set() |
|||
fullPath = os.path.join(root, f) |
|||
musicFiles[exts].add(fullPath) |
|||
|
|||
if len(musicFiles) >= 2: |
|||
log.warn("Different extensions for album {}. AlbumGain won't be on par.".format(albumName)) |
|||
|
|||
for exts, files in musicFiles.items(): |
|||
|
|||
if exts == ("flac",) and not FORCE: |
|||
allTagged = True |
|||
for f in files: |
|||
if not isFlacTagged(f): |
|||
allTaged = False |
|||
break |
|||
if allTagged: |
|||
log.debug("Already tagged (for flac only)!") |
|||
break |
|||
|
|||
cmd = GAIN_COMMANDS[exts] + list(files) |
|||
log.debug("Registering command: `{}`".format(" ".join(cmd))) |
|||
cmds.append(cmd) |
|||
|
|||
logging.info("Executing commands") |
|||
for cmd in progressbar.progressbar(cmds): |
|||
subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
|||
|
|||
|
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue