#!/usr/bin/env python3
import argparse
import stagger
from stagger.id3 import *
import taglib
import os.path
import sys
import subprocess

try:
    default_mdir = subprocess.check_output(['xdg-user-dir', 'MUSIC']).decode('UTF-8')
    default_mdir = default_mdir.strip()
except:
    default_mdir = os.path.expanduser('~/Music')
default_mdir += '/Sorted'

parser = argparse.ArgumentParser(description='Reorganize file layout according to tag')
parser.add_argument('files', metavar='file', nargs='+', help='file to reorganize')
parser.add_argument('--dry-run', '-n', action='store_true', help='do nothing, but print what would be done')
parser.add_argument('--dest', '-d', nargs=1, help='destination directory; defaults to $XDG_MUSIC_DIR/Sorted', default=default_mdir)

args = parser.parse_args()

def underscore_special(name):
    if name[-1] in ('.', ' '):
        name = name[:-1] + '_'
    if name[0] == '.':
        name = '_' + name[1:]
    new_name = ''
    for c in name:
        if ord(c) < 32 \
           or ord(c) == 127 \
           or c in ('/', '?', '<', '>',
                    '\\', ':', '*', '|', '"', '^'):
            new_name += '_'
        else:
            new_name += c
    return new_name

for file_name in args.files:
    i = file_name.rfind('.')
    extension = '' if i < 0 else file_name[i:].lower()
    if extension == '.mp3':
        try:
            t = stagger.read_tag(file_name)
            if t.title == '' \
               or t.album == '':
                print("Warning: Nonexistent or incomplete tag for " + file_name + ". Skipping...", file=sys.stderr)
                continue
            if TCMP in t and t[TCMP] == 1:
                new_file_dir1 = 'Compilations'
                new_file_name = ((("%d-" % t.disc) if t.disc > 0 else "")
                                 + (("%02d " % t.track) if t.track > 0 else "")
                                 + (t.artist if t.artist != '' else "")
                                 + t.title)
            else:
                if t.album_artist == '':
                    if t.artist == '':
                        print("Warning: Nonexistent or incomplete tag for " + file_name + ". Skipping...", file=sys.stderr)
                        continue
                    t.album_artist = t.artist
                new_file_dir1 = t.album_artist
                new_file_name = ((("%d-" % t.disc) if t.disc > 0 else "")
                                 + (("%02d " % t.track) if t.track > 0 else "")
                                 + t.title)
            new_file_dir2 = (t.album if t.album != '' else "Unknown Album")
        except stagger.errors.NoTagError:
            print("Warning: No tag for " + file_name + ". Skipping...", file=sys.stderr)
            continue
    elif extension in ('.mp4', '.m4a', '.m4b', '.m4p',
                       '.flac',
                       '.ogg', '.opus', '.spx', '.ogv', '.oga',
                       '.mpc', '.wv', '.ape', '.ofr', '.ofs',
                       '.wma'):
        t = taglib.File(file_name);
        if 'ALBUMARTIST' not in t.tags:
            if 'ARTIST' not in t.tags:
                print("Warning: No or incomplete tag for " + file_name + ". Skipping...", file=sys.stderr)
                continue
            t.tags['ALBUMARTIST'] = t.tags['ARTIST']
        if 'ALBUM' not in t.tags \
           or 'TITLE' not in t.tags:
            print("Warning: Nonexistent or incomplete tag for " + file_name + ". Skipping...", file=sys.stderr)
            continue
        new_file_dir1 = t.tags['ALBUMARTIST'][0]
        new_file_dir2 = t.tags['ALBUM'][0]
        new_file_name = ((("%d-" % int(t.tags['DISCNUMBER'][0])) if 'DISCNUMBER' in t.tags else "")
                         + (("%02d " % int(t.tags['TRACKNUMBER'][0])) if 'TRACKNUMBER' in t.tags else "")
                         + t.tags['TITLE'][0])
    else:
        print("Warning: Unrecognized file extension '"
              + extension + "' for '" + file_name + "'. Skipping...", file=sys.stderr)
        continue
    new_file_dir1 = underscore_special(new_file_dir1)
    new_file_dir2 = underscore_special(new_file_dir2)
    new_file_name = underscore_special(new_file_name)
    new_file_name = args.dest + '/' + new_file_dir1 + '/' + new_file_dir2 + '/' + new_file_name + extension
    if os.path.abspath(file_name) == os.path.abspath(new_file_name):
        continue
    elif os.path.exists(new_file_name):
        print("Warning: File '" + new_file_name + "', to which file '"
              + file_name + "' was being moved, already exists. Skipping...", file=sys.stderr)
    if args.dry_run:
        print("os.rename(%s, %s)" % (repr(file_name), repr(new_file_name)))
    else:
        os.renames(file_name, new_file_name)
