#!/usr/bin/python
# -*- coding: UTF-8 -*-

# Copyright (c) 2006-2008 Stephan Windmüller <windy@white-hawk.de>
# This code is hereby licensed for public consumption under the
# GNU GPL v2 or greater.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.

"""
dagger handles tags and filenames.
"""

__revision__ = "0.3.2"

import re

class GenreNotFoundException(Exception):

    "Is raised when id3v2 does not know the genre."

    def __init__(self, value):
        Exception.__init__(self, value)
        self.value = value
    def __str__(self):
        return str(self.value)

class RegexpError(Exception):

    "Is raised when parsing of a regexp string fails."
    
    def __init__(self, value):
        Exception.__init__(self, value)
        self.value = value
    def __str__(self):
        return str(self.value)

def rename(oldname, newname):

    "Does the actual renaming"

    global newnames

    # If there is no change in filename, just exit

    if oldname == newname or "./" + oldname == newname:
        raise IOError('samefile')

    dir_exists = 1

    # Check if target directory exists

    dirname = os.path.dirname(newname)
    if dirname != '' and not os.path.isdir(dirname):
        if not dry_run and '--create-dirs' in options_hash.keys():
            os.makedirs(dirname)
        elif not '--create-dirs' in options_hash.keys():
            if not quiet:
                print "Cannot move file: Directory '" + dirname + \
                "' does not exist."
            dir_exists = 0
            raise IOError('dirmissing')

    # Prevent existing files from being overwritten

    if os.path.isfile(newname) or newname in newnames and dir_exists:
        if not '--force' in options_hash.keys():
            if not quiet:
                print "Not renaming '" + oldname + "' to '" + newname + \
                "': File exists or will be existing!"
            raise IOError('file_existing')
            newnames.append(newname)
        elif not dry_run:
            try:
                os.rename(oldname, newname)
            except OSError, exception:
                if not quiet:
                    print "Error while trying to rename: " + str(exception)
    elif dry_run:
        newnames.append(newname)
    elif dir_exists:
        # All checks done, rename!
        try:
            os.rename(oldname, newname)
        except OSError, exception:
            if not quiet:
                print "Error while trying to rename: " + str(exception)



def parseformat(format, curtagobj, filename):

    "Returns the filename with tags replaced"

    newstr = ''

    suffix = format.split(".")[-1:][0]

    while len(format) > 0:
        if format[0] == '%':
            if format[:2] in valid_tags:
                try:
                    newstr += curtagobj.tag[format[:2]].replace('/','-')
                except KeyError:
                    if not quiet:
                        print filename + " does not have " + \
                        format[:2] + "-Tag"
                format = format[2:]
            else:
                newstr = newstr + format[0]
                format = format[1:]
        else:
            newstr = newstr + format[0]
            format = format[1:]

    # Add suffix if missing

    if not '--no-suffix' in options_hash.keys() and \
    suffix.lower() not in ['ogg', 'mp3']:
        newstr += '.' + filename.split(".")[-1:][0]

    return newstr



def action_rename(filename, curtagobj, format, basedir):

    "Renames a file to the given format."

    global files_existing
    global files_dirmissing
    global newnames

    # Do not rename if tag is empty
    if curtagobj.tag == {}:
        return

    if basedir == '':
        # Basedir was not given, leave files in their directory
        if os.path.dirname(filename) == '':
            newname = parseformat(format, curtagobj, filename)
        else:
            newname = os.path.dirname(filename) + '/' +\
            parseformat(format, curtagobj, filename)
    else:
        newname = basedir + parseformat(format, curtagobj, filename)

    if (filename != newname) and (verbose or dry_run):
        print "Old: " + filename
        print "New: " + newname

    # Rename file 'filename' to 'newname'

    try:
        rename(filename, newname)
    except IOError, error_type:
        if str(error_type) == 'samefile':
            newnames.append(filename)
        elif str(error_type) == 'dirmissing':
            files_dirmissing += 1
        elif str(error_type) == 'file_existing':
            files_existing += 1
            newnames.append(newname)

    return newname


def static_override(curtagobj):

    "Sets all static values which are given via command line"

    for key in format_static.keys():
        cl_option = '--set-' + format_static[key]
        if cl_option in options_hash.keys():
            if verbose or dry_run:
                print "Overriding " + format_static[key].upper() + \
                " tag with static \"" + options_hash[cl_option] + '"'
            curtagobj.set_tag(key, options_hash[cl_option])


def set_tracknum(filename, curnum):
    
    "Sets the track number in all files automatically."

    curnum += 1
    if tracknum < 10:
        tagobj.set_tag('%n', '0' + str(curnum))
    else:
        tagobj.set_tag('%n', str(curnum))

    if verbose or dry_run:
        print filename
        print "Setting track number to: " + tagobj.tag['%n']

    return curnum


def get_filetag_regex(format):

    "Parse format string and generate regex."

    tags = []
    regex = '\A'

    if format.find(".") > 0:
        suffix = format.split(".")[-1:][0]
    else:
        suffix = ''

    while len(format) > 0:
        if format[0] == '%' and format[:2] in valid_tags:
            tags.append(format[:2])
            regex = regex + "(.*?)"
            format = format[2:]
        elif format[0] == '%' and format[:2] == '%x':
            regex = regex + ".*"
            format = format[2:]
        else:
            regex = regex + re.escape(format[0])
            format = format[1:] 

    if not '--no-suffix' in options_hash.keys() and suffix == '':
        regex += '\..*'

    return [re.compile(regex + '\Z'), tags]


def action_filetag(filename, formatdata):

    "Retrieves tags from filenames."

    regex = formatdata[0]
    tags = formatdata[1]

    # Set tags in all files

    matcher = regex.match(filename)
    if matcher != None:
        counter = len(tags)
        while counter > 0:
            tagobj.set_tag(tags[counter-1], matcher.group(counter))
            counter -= 1
    elif not quiet:
        print "Filename does not match format string!"


class Tag:

    "Provides a generic class for ogg and mp3 tags."

    def __init__ (self):
        self.tag = {}
        self.filetype = ''
        self.changed = 0



    def load_tags (self, filename):

        "Loads the tag information stored in an ogg or mp3 file."

        ogg_regex = {
            'title=(.*)':              '%t',
            'artist=(.*)':             '%a',
            'album=(.*)':              '%b',
            'date=(.*)':               '%y',
            'genre=(.*)':              '%g',
            'tracknumber=(\d*)':       '%n',
            'tracknumber=\d*/(\d*)':   '%l',
            'tracktotal=(.*)':         '%l',
            'comment=(.*)':            '%c',
        }

        mp3_regex = {
            'Title\s*:\ (.*)\S*Artist:\ .*':    '%t',
            'Title\s*:\ .*\S*Artist:\ (.*)':    '%a',
            'Album\s*:\ (.*)\S*Year:\ \d*,\ Genre:\ .*\ \(\d*\)':  '%b',
            'Album\s*:\ .*\S*Year:\ (\d*),\ Genre:\ .*\ \(\d*\)':  '%y',
            'Album\s*:\ .*\S*Year:\ \d*,\ Genre:\ (.*)\ \(\d*\)':  '%g',
            'Comment:\ (.*)\S*Track:\ \d*':     '%c',
            'Comment:\ .*\S*Track:\ (\d*)':     '%n',
            'TIT2\ \(.*?\):\ (.*)':             '%t',
            'TPE1\ \(.*?\):\ (.*)':             '%a',
            'TALB\ \(.*?\):\ (.*)':             '%b',
            'TYER\ \(.*?\):\ (.*)':             '%y',
            'TRCK\ \(.*?\):\ (\d*)':            '%n',
            'TRCK\ \(.*?\):\ .*/(.*)':          '%l',
            'TCON\ \(.*?\):\ (.*)\ \(\d*\)':    '%g',
            'COMM\ \(.*?\):\ (.*)':             '%c',
            'TT2\ \(.*?\):\ (.*)':              '%t',
            'TP1\ \(.*?\):\ (.*)':              '%a',
            'TAL\ \(.*?\):\ (.*)':              '%b',
            'TYE\ \(.*?\):\ (.*)':              '%y',
            'TRK\ \(.*?\):\ (\d*)':             '%n',
            'TRK\ \(.*?\):\ .*/(.*)':           '%l',
            'TCO\ \(.*?\):\ (.*)':              '%g',
            'COM\ \(.*?\):\ (.*)':              '%c',
            }

        filename = filename.replace("`","\`")
        filename = filename.replace('"','\\"')

        suffix = filename.split(".")[-1:][0]

        # Retrieve tags with external tools

        if suffix.lower() == 'ogg':
            output = os.popen('vorbiscomment -l "' + filename + '"')
            work_regex = ogg_regex
            self.filetype = 'ogg'
        elif suffix.lower() == 'mp3':
            output = os.popen('id3v2 -R "' + filename + '"')
            work_regex = mp3_regex
            self.filetype = 'mp3'

        for line in output:
            line = line.lstrip()
            for regex in work_regex:
                matcher = re.match(regex, line, re.I)
                if matcher != None and matcher.group(1).rstrip() != '':
                    self.tag[work_regex[regex]] = matcher.group(1).rstrip()

        # Check if command was successful

        exitcode = output.close()

        if exitcode != None:
            if not quiet:
                print "An error occured while reading tags. Aborting!"
            sys.exit(0)

        self.changed = 0

        # Normalize title

        self.normalize()

        # Pad numbers

        for pad_key in ['%n', '%l']:
            if self.tag.has_key(pad_key):
                try:
                    padded_tag = '%02d' % int(self.tag[pad_key])
                except ValueError:
                    # Tag is not a number, do not touch
                    padded_tag = self.tag[pad_key]
                    if not quiet:
                        print "Error parsing tag " + pad_key + " from " + filename
                self.set_tag(pad_key, padded_tag)

    def normalize(self):

        "Normalizes the title tag"

        if not '--normalize' in options_hash.keys() or not\
        self.tag.has_key('%t') or '--set-title' in options_hash.keys():
            return

        articles = ['a', 'an', 'the']
        conjunctions = ['and', 'but', 'or', 'nor']
        short = ['as', 'at', 'by', 'for', 'in', 'of', 'on', 'to']
        other = ['feat.']
        do_not = articles + conjunctions + short + other

        # Replace underscores and backticks

        output = self.tag['%t'].replace('_', ' ')
        output = output.replace('`', "'")

        # First letter uppercase for most words

        def parcapitalize(word):

            "Capitalizes a word and takes care of parenthesis."

            if word[0] == "(":
                return "(" + parcapitalize(word[1:])
            elif word.find('-') > -1:
                capparts = []
                parts = word.split('-')
                for part in parts:
                    capparts.append(part.capitalize())
                return '-'.join(capparts)
            else:
                return word.capitalize()


        words = output.split(' ')
        counter = 1
        while counter < len(words)-1:
            if words[counter].lower() in do_not:
                words[counter] = words[counter].lower()
            else:
                words[counter] = parcapitalize(words[counter])
            counter += 1

        # Always capitalize first and last word

        words[0] = parcapitalize(words[0])
        words[len(words)-1] = parcapitalize(words[len(words)-1])

        output = ' '.join(words)

        if self.tag['%t'] != output:
            if verbose or dry_run:
                print '"' + self.tag['%t'] + '"' + \
                " normalized to: " + '"' + output + '"'
            self.tag['%t'] = output
            self.changed = 1


    def save_ogg_tags(self, filename):

        "Saves tags for OGG Vorbis files."

        tag = self.tag.copy()

        ogg_key = {
            '%t': 'TITLE=',
            '%a': 'ARTIST=',
            '%b': 'ALBUM=',
            '%y': 'DATE=',
            '%g': 'GENRE=',
            '%l': 'TRACKTOTAL=',
            '%n': 'TRACKNUMBER=',
            '%c': 'COMMENT=',
            }

        comment = os.popen('vorbiscomment -l "' + \
        filename.replace('`','\`') + '"')
        setcmd = ['vorbiscomment', '-w']

        # Overwrite original tags

        for line in comment:
            overwritten = 0
            for key in ogg_key.keys():
                if line.lower().find(ogg_key[key].lower()) == 0 \
                and tag.has_key(key):
                    setcmd.append('-t' + ogg_key[key] + tag[key])
                    del tag[key]
                    overwritten = 1
            if not overwritten:
                setcmd.append('-t' + line[:-1])

        # Add new tags

        for key in tag.keys():
            setcmd.append('-t' + ogg_key[key] + tag[key])
                         
        setcmd.append(filename)

        if not dry_run:
            os.spawnvp(os.P_WAIT, 'vorbiscomment', setcmd)



    def id3v1_options (self):

        "Return command line options for setting id3v1."

        def get_genrenum (genre):

            "Retrieves the genre number used by id3v2."

            allgenres = os.popen('id3v2 -L')

            regex = re.compile('\A\s*(\d*):\ (.*)\Z')

            for line in allgenres:
                matcher = regex.match(line[:-1])
                if matcher != None and matcher.group(2) == genre:
                    return matcher.group(1)

            raise GenreNotFoundException('Genre "' +\
            genre + '" could not be found! id3v1 tags may look garbled.')



        mp3_key = {
            '%t': 'song',
            '%a': 'artist',
            '%b': 'album',
            '%y': 'year',
            '%n': 'track',
            '%g': 'genre',
            '%c': 'comment'
        }

        cl_options = []

        for key in mp3_key.keys():
            if self.tag.has_key(key):
                if key == '%n':
                    # Different format if number of tags is given
                    if self.tag.has_key('%l'):
                        trck = self.tag['%n'] + '/' + self.tag['%l']
                    else:
                        trck = self.tag['%n']
                    cl_options.append('--' + mp3_key[key] + '=' + trck)
                elif key == '%g':
                    # Genre needs a number in id3v1
                    try:
                        cl_options.append('--' + mp3_key[key] + '=' + \
                        str(get_genrenum(self.tag[key]))) 
                    except GenreNotFoundException, exception:
                        if not quiet:
                            print exception
                else:
                    cl_options.append('--' + mp3_key[key] + '=' + \
                    self.tag[key])

        return cl_options



    def id3v2_options (self):

        "Return command line options for setting id3v2."

        mp3_key = {
            '%t': 'TIT2',
            '%a': 'TPE1',
            '%b': 'TALB',
            '%y': 'TYER',
            '%n': 'TRCK',
            '%g': 'TCON',
            '%c': 'COMM'
        }

        cl_options = []

        for key in mp3_key.keys():
            if self.tag.has_key(key):
                if key == '%n':
                    # Different format if number of tags is given
                    if self.tag.has_key('%l'):
                        trck = self.tag['%n'] + '/' + self.tag['%l']
                    else:
                        trck = self.tag['%n']
                    cl_options.append('--' + mp3_key[key] + '=' + trck)
                else:
                    cl_options.append('--' + mp3_key[key] + '=' + \
                    self.tag[key])

        return cl_options


    def missing (self, filename, fields):

        "Checks for missing tag fields"

        while len(fields) > 0:
            key = "%" + fields[0]

            if verbose:
                print "Checking for tag " + key


            if not self.tag.has_key(key) and not quiet:
                print filename + " has no " + format_static[key] + "-tag"

            fields = fields[1:]



    def regexp (self, regexp):

        "Performs a regexp replace."

        key = '%' + regexp[0]

            
        if key in format_static.keys():
            keys = [key]
        elif key == '%s':
            keys = format_static.keys()
        else:
            if not quiet:
                print "Error in regexp value: Unknown key!"
                sys.exit(1)
        
        try:
            (expr, subst, modifiers) = self.parse_regexp(regexp)
        except RegexpError, message:
            print message
            sys.exit(1)
            
        num_subst = 1 
        flags = 0
        if "global" in modifiers:
            num_subst = 0
        if "case insensitive" in modifiers:
            flags = flags | re.I
            
        comp_expr = re.compile(expr, flags)
        
        for key in keys:
            if self.tag.has_key(key):
                replaced = re.sub(comp_expr, subst, self.tag[key], num_subst)
                if (replaced != self.tag[key]):
                    if verbose or dry_run:
                        print "Regexp: " + self.tag[key] + "  ->  " + replaced
                self.tag[key] = replaced
                self.changed = 1
    
    def parse_regexp(self, regexp):

        """
        Parses the value of --regexp.
        Returns expression, substitution and modifiers
        """

        knownModifiers = { "g": "global", "i": "case insensitive"}
        state = None
        escaped = False
        read_chars = []
        buffer = []
        expression = None
        substitution = None
        modifiers = [] 
        
        for char in regexp:
            if state == "End":
                # chars after end of expression
                raise RegexpError("regexp error at char %d: garbage after end of substitution" % (len(read_chars)+1))
            elif state == "Start":
                if char != '/':
                    # syntax error: key more than one char
                    raise RegexpError("regexp error at char %d: garbage before expression" % (len(read_chars)+1))
                else:
                    # start of expression
                    state = "BufferAdd"
            elif state == "BufferAdd":
                if char == '/' and not escaped:
                    # end of expression, copy buffer and go to next char
                    if expression is None:
                        expression = buffer
                    else:
                        substitution = buffer
                        state = "Mod"
                    buffer = []
                    read_chars.append(char)
                    continue
                    
                # handle escaped chars
                if char == '\\' and not escaped:
                    escaped = True
                elif escaped:
                    escaped = False

                buffer.append(char)
            elif state == "Mod":
                if char in knownModifiers:
                    modifiers.append(knownModifiers[char])
                else:
                    raise RegexpError("regexp error at char %d: unknown modifier" % (len(read_chars)+1))
            else: 
                state = "Start"
            read_chars.append(char)
            # print "state: %s, escaped: %s, char: %s" % (state, escaped, char)
        
        expr = "".join(expression)
        subst = "".join(substitution)
        return (expr, subst, modifiers)

    def save_mp3_tags (self, filename):

        "Saves tags for MP3 files."

        setcmd = ['id3v2']

        if '--no-id3v2' in options_hash:
            setcmd += ['-1']
        else:
            setcmd += self.id3v2_options()

        if '--no-id3v1' in options_hash:
            setcmd += ['-2']
        else:
            setcmd += self.id3v1_options()

        setcmd.append(filename)
        if not dry_run:
            os.spawnvp(os.P_WAIT, 'id3v2', setcmd)

        if not dry_run:
            os.spawnvp(os.P_WAIT, 'id3v2', setcmd)


    def save_tags (self, filename):

        "Saves tag info into ogg or mp3."

        # Normalize title
        self.normalize()

        if not self.changed:
            # Do not save if nothing changed
           return

        if self.filetype == 'ogg':
            self.save_ogg_tags(filename)
        elif self.filetype == 'mp3':
            self.save_mp3_tags(filename)

        self.changed = 0



    def set_tag (self, key, value):

        "Sets a single tag."

        if self.tag.has_key(key) and self.tag[key] != value:
            if verbose or dry_run:
                print "Changing " + format_static[key].upper() +\
                " from \"" + self.tag[key] + '"'\
                " to " + '"' + value + '"'
            self.changed = 1
        elif not self.tag.has_key(key):
            if verbose or dry_run:
                print "Setting " + format_static[key].upper() +\
                " to \"" + value + '"'
            self.changed = 1

        self.tag[key] = value


def usage():

    "Prints the valid syntax for dagger."

    print "dagger " + __revision__
    print "Copyright (c) 2006-2008 Stephan Windmüller\n"
    print "Syntax: " + sys.argv[0] + " [options] [actions] file(s)"
    print "Example: " + sys.argv[0] + " -v -r \"%b/%n - %a - %t.ogg\" *.ogg"
    print """
General actions:
 -h, --help                     Show this help
 -r, --rename="format"          Renames the given file(s) to format
 -t, --tag="format"             Parses the filename and saves the tag
 -m, --missing                  Checks for missing tag fields
     --regexp="s/str1/str2/"    Perform regexp replace

Actions which set static tags:  
     --set-artist="name"        Sets the artist tag in all files
     --set-album="name"         Sets the album tag in all files
     --set-comment="name"       Sets the comment tag in all files
     --set-genre="genre"        Sets the genre tag in all files
     --set-tracktotal="num"     Sets the total number of tracks
     --set-auto-tracknum        Sets the track number automatically
     --set-title="title"        Sets the title tag in all files
     --set-date="year"          Sets the date tag in all files

Options:
     --basedir="dir"            Move file relative to "dir" while renaming
     --create-dirs              Create needed directories while renaming
 -d, --dry-run                  Do not change files, only show what would happen
     --force                    Allow overwriting of existing files
     --missing-format="fields"  Tags to look at when check for missing ones
     --no-id3v1                 Do not save id3v1 tags
     --no-id3v2                 Do not save id3v2 tags
     --no-suffix                Do not add suffix to format string if missing
     --normalize                Normalize title
     --profile="profile"        Use profile in ~/.daggerrc
 -q, --quiet                    Do not produce any output
     --recursive                Proceed recursive in all subdirectories
 -v, --verbose                  Be verbose

Format may have the following fields:

        %a: ARTIST          %l: TRACKTOTAL
        %b: ALBUM           %n: TRACKNUMBER
        %c: COMMENT         %t: TITLE
        %g: GENRE           %y: DATE
                            %x: ignore this
"""

#####################################################################
#
# Main program
#

import getopt
import sys
try:
    options, files = getopt.getopt(sys.argv[1:], 'dhr:t:mqv',
        ["basedir=","create-dirs","dry-run","force","help","missing",\
        "missing-format=","no-id3v1","no-id3v2","no-suffix","normalize",\
        "profile=","quiet","rename=","recursive","regexp=","set-album=",\
        "set-artist=","set-comment=","set-date=","set-genre=",\
        "set-title=","set-auto-tracknum","set-tracktotal=",\
        "tag=","verbose"])
except getopt.GetoptError:
    print "Error in arguments!"
    usage()
    sys.exit(2)

# When there are no options or files, print usage and exit

if options == [] or files == []:
    usage()
    sys.exit(0)

# Setting default options

dry_run = 0
quiet = 0
recursive = 0
verbose = 0

format_static = {
    '%t': 'title',
    '%a': 'artist',
    '%b': 'album',
    '%y': 'date',
    '%g': 'genre',
    '%l': 'tracktotal',
    '%n': 'tracknumber',
    '%c': 'comment',
}

valid_tags = format_static.keys()

# Setting options

options_hash = {}

import os
if os.path.exists(os.path.expanduser('~/.daggerrc')):
    import ConfigParser
    config = ConfigParser.ConfigParser()
    config.read([os.path.expanduser('~/.daggerrc')])

    # Set values of default section

    for option, argument in config.items('default'):
        options_hash['--' + option] = argument

    # Set profile values, if a profile is given

    for option, argument in options:
        if option == '--profile':
            for option, argument in config.items(argument):
                options_hash['--' + option] = argument

            # Clear options which are set to 0
            for optionkey in options_hash.keys():
                if options_hash[optionkey] == '0':
                    options_hash.pop(optionkey, options_hash[optionkey])

for option, argument in options:

    options_hash[option] = argument

    if option == '-d' or option == '--dry-run':
        dry_run = 1
    if option == '-q' or option == '--quiet':
        verbose = 0
        quiet = 1
    if option == '--recursive':
        recursive = 1
    if option == '-v' or option == '--verbose':
        verbose = 1
        quiet = 0

if options_hash.has_key('-h') or options_hash.has_key('--help'):
    usage()
    sys.exit(0)

# Do main action

if recursive:
    # Get all files in subdirectories
    for checkfile in files:
        if os.path.isdir(checkfile):
            files.remove(checkfile)
            for root, dirs, walkfiles in os.walk(checkfile, topdown=False):
                for walkfile in walkfiles:
                    walkname, walkext = os.path.splitext(walkfile)
                    if walkext.lower() in ['.ogg', '.mp3']:
                        files.append(root + '/' + walkfile)

# Check if all filenames are valid

for checkfile in files:
    if not os.path.isfile(checkfile):
        if not quiet:
            print "Error: " + checkfile + " is not a file!"
            if not recursive:
                print "Use --recursive to proceed subdirectories."
        sys.exit(1)

files_dirmissing = 0
files_existing = 0
newnames = []
tracknum = 0

if options_hash.has_key('-t') or options_hash.has_key('--tag'):
    if options_hash.has_key('-t'):
        format_data = get_filetag_regex(options_hash['-t'])
    else:
        format_data = get_filetag_regex(options_hash['--tag'])

# If a basedir was given, ensure it ends with a /

if options_hash.has_key('--basedir'):
    basedir = options_hash['--basedir']
    if basedir[-1:] != '/':
        basedir = basedir + '/'
else:
    basedir = ''

for curfile in files:

    # Do not handle non-audio-files
    if curfile[-4:].lower() in ['.ogg', '.mp3']:

        if verbose or dry_run:
            print "Processing " + curfile + "...\n"

        tagobj = Tag()
        tagobj.load_tags(curfile)

        if options_hash.has_key('--set-auto-tracknum'):
            tracknum = set_tracknum(curfile, tracknum)

        if options_hash.has_key('-t') or options_hash.has_key('--tag'):
            action_filetag(curfile, format_data)

        if options_hash.has_key('--regexp'):
            tagobj.regexp(options_hash['--regexp'])

        static_override(tagobj)

        tagobj.save_tags(curfile)

        if options_hash.has_key('-r'):
            curfile = action_rename(curfile, tagobj, options_hash['-r'], basedir)
        elif options_hash.has_key('--rename'):
            curfile = action_rename(curfile, tagobj, options_hash['--rename'], basedir)

        if options_hash.has_key('-m') or options_hash.has_key('--missing'):
            if options_hash.has_key('--missing-format'):
                missing_format = options_hash['--missing-format']
            else:
                missing_format = "abglnty"

            tagobj.missing(curfile, missing_format)

    elif not quiet:
        print "Error: " + curfile + " is not a known audio file!"

    if verbose or dry_run:
        print "--------------------------------------------------"

if files_dirmissing > 0 and not quiet:
    print "\n" + str(files_dirmissing),
    print "files not moved because their directories did not exist."
    print "Use --create-dirs to do it anyway."

if files_existing > 0 and not quiet:
    print "\n" + str(files_existing),
    print "files not renamed because their names exist. " + \
    "Use --force to do it anyway."

sys.exit(0)
