#!/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)