#!/usr/bin/python

# MP3FileInfo.py
#       --copyright--                   Copyright 2007 (C) Tranzoa, Co. All rights reserved.    Warranty: You're free and on your own here. This code is not necessarily up-to-date or of public quality.
#       --url--                         http://www.tranzoa.net/tzpython/
#       --email--                       pycode is the name to send to. tranzoa.com is the place to send to.
#       --bodstamps--
#       May 9, 2003             bar
#       May 12, 2003            bar     escape ampersands, too
#                                       move escape routine over to MusicMetaData
#                                       untested
#       May 14, 2003            bar     put "r" in front of the regx patterns
#       May 15, 2003            bar     get rid of unused private routines
#       May 31, 2005            bar     close open files
#       November 1, 2005        bar     able to get duration from tags
#                                       url and audio_url
#       November 18, 2007       bar     turn on doxygen
#       November 27, 2007       bar     insert boilerplate copyright
#       December 1, 2007        bar     use tz_parse_time's mktime routine to get the 1st second of the song's year - rather than one that includes the PC's time zone
#       May 12, 2008            bar     don't use id as a variable name
#       May 17, 2008            bar     email adr
#       November 29, 2011       bar     pyflake cleanup
#       May 27, 2012            bar     doxygen namespace
#       January 18, 2016        bar     except statement fix
#                                       typo in cmd line code
#       August 18, 2019         bar     update command line handling
#       February 8, 2021        bar     date field
#       --eodstamps--
##      \file
#       \namespace              tzpython.MP3FileInfo
#
#

import re
import string

import tz_parse_time


from MP3Info import MP3Info

class MP3FileInfo :

    def __init__(me, file_name) :
        """
            MP3FileInfo

            An object of this class encapsulates certain information
            that can be gathered from an MP3 file.

            Specifically, it gathers ID3 tags, versions 1, 2.2, and
            2.3 (using the MP3Info.py module's classes and logic).

            And it gather file information.

            It throws an IO exception if it cannot open or read the
            given MP3 file.

        """

        me.valid        = 0             # 1 if this thing was created ok

        me.artist       = ""
        me.title        = ""
        me.album        = ""
        me.disc         = ""
        me.track        = ""
        me.year         = ""
        me.date         = ""
        me.genre        = ""
        me.url          = ""
        me.audio_url    = ""

        me.duration     = 0

        me.file_size    = 0




        f  = open(file_name, 'rb')

        f.seek(0, 2)
        me.file_size    = f.tell()

        i  = MP3Info(f)

        f.close()

        if i.id3 :
            if hasattr(i, 'artist') :
                me.artist   = string.strip(i.artist)
                me.valid    = 1

            if hasattr(i, 'title') :
                me.title    = string.strip(i.title)
                me.valid    = 1

            if hasattr(i, 'album') :
                me.album    = string.strip(i.album)
                me.valid    = 1

            if hasattr(i, 'url') :
                me.url      = string.strip(i.url)
                me.valid    = 1

            if hasattr(i, 'audio_url') :
                me.audio_url    = string.strip(i.audio_url)
                me.valid        = 1

            if hasattr(i, 'disc') :
                v = re.match(r"\d+", string.strip(str(i.disc)))
                if ((v != None) and (int(v.group(0)) > 0)) :
                    me.disc     = v.group(0)
                    me.valid    = 1

            if hasattr(i, 'track') :
                v = re.match(r"\d+", string.strip(str(i.track)))
                if ((v != None) and (int(v.group(0)) > 0)) :
                    me.track    = v.group(0)
                    me.valid    = 1

            if hasattr(i, 'duration') :
                v = re.match(r"\d+", string.strip(str(i.duration)))
                if ((v != None) and (int(v.group(0)) > 0)) :
                    me.duration = str(int(v.group(0)) / 1000)
                    me.valid    = 1

            if hasattr(i, 'year') :
                v = re.match(r"\s*(\d+)", string.strip(str(i.year)))
                if ((v != None) and (int(v.group(0)) > 0)) :
                    me.year     = int(v.group(0))
                    me.valid    = 1
                    if ((me.year >= 1970) and (me.year < 2030)) :
                        me.date     = int(tz_parse_time.mktime( ( me.year, 1, 1, 0, 0, 0, 0, 1, -1 ) ))

            if hasattr(i, 'date') :
                v = re.search(r"^\x03(\d\d\d\d)(?:-(\d\d)(?:-(\d\d)(?:T(\d\d)(?::(\d\d)(?::(\d\d))?)?)?)?)?", str(i.date))
                if  v != None   :
                    me.date     = int(v.group(1))
                    me.valid    = 1
                    if ((me.date >= 1970) and (me.date < 2030)) :
                        me.date     = int(tz_parse_time.mktime( ( me.date, int(v.group(2) or 1) , int(v.group(3) or 1), int(v.group(4) or 0), int(v.group(5) or 0), int(v.group(6) or 0), 0, 1, -1 ) ))

            if hasattr(i, 'genre') :
                v = string.strip(i.genre)
                v = re.sub(r"\(.*\)", "", v)
                me.genre    = v
                me.valid    = 1

            if i.mpeg.valid :
                if (i.mpeg.total_time > 0) :
                    me.duration = i.mpeg.total_time
                    me.valid    = 1
                pass
            pass

        pass


    pass


#
#
#       Test code (takes MP3 file names or "@" files - files containing names of files):
#
#           shell prompt: python MP3FileInfo.py file_name ...
#
#           shell prompt: python MP3FileInfo.py @file_name ...
#
#
if __name__ == '__main__':

    from MusicMetaData import escape_str

    def show_mp3_info(file_name, sid = 0) :

        try :
            mi = MP3FileInfo(file_name);

            if mi.valid :

                sid    += 1

                print "<id_info>"

                print "  <id>"        + str(sid)                      + "</id>"

                print "  <full_id>"   + str(sid)                      + "</full_id>"
                print "  <clip_id>"   + ""                            + "</clip_id>"
                print "  <quick_id>"  + ""                            + "</quick_id>"

                print "  <file_name>" + escape_str(file_name)         + "</file_name>"
                print "  <audio_url>" + escape_str(mi.audio_url)      + "</audio_url>"
                print "  <url>"       + escape_str(mi.url)            + "</url>"

                print "  <artist>"    + escape_str(mi.artist)         + "</artist>"
                print "  <title>"     + escape_str(mi.title)          + "</title>"
                print "  <album>"     + escape_str(mi.album)          + "</album>"
                print "  <disc>"      + escape_str(mi.disc)           + "</disc>"
                print "  <track>"     + escape_str(mi.track)          + "</track>"
                print "  <genre>"     + escape_str(mi.genre)          + "</genre>"
                print "  <year>"      + escape_str(str(mi.year))      + "</year>"
                print "  <date>"      + escape_str(str(mi.date))      + "</date>"

                print "  <duration>"  + escape_str(str(mi.duration))  + "</duration>"

                print "  <file_size>" + escape_str(str(mi.file_size)) + "</file_size>"

                print "</id_info>"
                print

        except IOError as (errno, strerror) :
            # print "I/O error(%s): %s : %s" % (errno, strerror, file_name)
            # print
            pass

        return(sid)



    import  glob
    import  os
    import  sys

    import  tzlib
    import  TZCommandLineAtFile

    program_name        = os.path.basename(sys.argv[0] or __file__ or __doc__.split()[0])

    args                = list(sys.argv[1:])

    TZCommandLineAtFile.expand_at_sign_command_line_files(args)

    if  not len(args) :

        print "Tell me an MP3 file!"

    else    :

        recurse = False


        def do_fn(fn, sid) :
            if  os.path.isdir(fn) :
                if  recurse :
                    fn  = os.path.join(fn, "*")
                else    :
                    fn  = os.path.join(fn, "*.mp3")
                pass
            for mfn in glob.glob(fn) :
                if  recurse and os.path.isdir(mfn) :
                    fns = glob.glob(os.path.join(mfn, os.path.basename(fn)))
                    fns.sort(lambda a, b : cmp(a.lower(), b.lower()))
                    for sfn in fns :
                        sid = do_fn(sfn, sid)
                    pass
                elif os.path.isfile(mfn) :
                    sid = show_mp3_info(fn, sid)
                pass
            return(sid)


        while True :
            oi  = tzlib.find_argi_and_del(args, [ "--sub_dirs", "-s", "--recurse", "--recursive", "-r", ])
            if  oi < 0 :
                break
            recurse = True

        sid =   0
        for a  in args :
            sid = do_fn(tzlib.expand_user_vars(a), sid)
        pass
    pass


#
#
#
# eof
