#!/usr/bin/env python
### mp3tagedit.py - a MP3 tageditor with which you can automate tagging
### Copyright (C) 1999  Arne Zellentin <arne@unix-ag.org>

### This program is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.

### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
### GNU General Public License for more details.

### 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

### see http://www.home.unix-ag.org/arne/scripToys/ for details.
#
# usage: mp3tagedit.py <file1> [<file2>, ..., <filen>]
# how it works? - figure it out yourself.

from sys import argv
from string import upper,lower,uppercase
from posix import fork
from os import execvp,wait
from readline import *
from re import compile

ACT,DEF,CMD,DSC,MAX=0,1,2,3,4
# Format: [actual value] [default] [mp3info flag] [human readable] [priority]
attrib={ "a": ["","+","-a","artist",30], "t": ["","+","-t","title",30],
         "l": ["","","-l","album",30],
         "y": ["","","-y","year",4], "c": ["","","-c","comment",30],
         "g": ["","","-G","genre",30] }
# if default=="+": ask for this tag
# if default=="*": determine this tag from regexp
attrib_keys="atlycg"
# be sure to update attrib_keys if you change attrib!

regexp=compile(r"^(?P<a>.*?) \((?P<l>[^\)]*) (?P<n>.*?)\) - (?P<t>.*)\.mp3$")
# example:       "artistarti  (album albumal tracknum000) - title titl.mp3"

all_tags=""
for i in attrib_keys:
  all_tags=all_tags+i

def read_check_len(prompt,which):  # which must be one of attrib's keys()
  global menu               # this is set here and reset only outsidy my scope
  tmp=raw_input(prompt)
  if len(tmp) > attrib[which][MAX]:
    print
    print "WARNING: "+attrib[which][DSC]+" exceeds 30 characters. [x] entering menu."
    print
    menu=1
  if tmp and tmp[-1]=="#":
    tmp=tmp[:-1]
    menu=1
    print
    print '[x] remove "#" and enter menu.'
    print
  return tmp

def print_defaults():
  tmp=[]
  for j in attrib_keys:
    tmp.append(attrib[j])
  print "[x] defaults are",
  tmp=filter(lambda x: x[DEF],tmp)
  if tmp:
    for j in tmp:
      if j[DEF]=="+":
        print "[ask for "+j[DSC]+"]",
      elif j[DEF]=="*":
        print "[match "+j[DSC]+"]",
      elif j[DEF]=="-":
        print "[clear "+j[DSC]+"]",
      else:
        print j[DSC]+'="'+j[DEF]+'"',
    print
  else:
    print "none."


def print_changes():
  tmp=[]
  for j in attrib_keys:
    tmp.append(attrib[j])
  tmp=filter(lambda x: x[ACT],tmp)
  if tmp:
    print "    [x] Changes are:"
    tmp.sort
    for j in tmp:
      if j[ACT]=="-":
        print "        [x] [clear "+j[DSC]+"]"
      else:
        print "        [x] "+j[DSC]+'="'+j[ACT]+'"'
    print
  else:
    print "    [x] Nothing changed (yet)."

def my_system(program,args):
  CHILD=0
  pid=fork()
  if pid==CHILD:
    execvp(program,args)
  else:
    status=wait()
  
print """
          << mp3 tag editor V1.1re (C) 1998 Arne Zellentin >>

In the following menu you can alter the defaults by entering the given
_uppercase_ letters. After leaving the menu (with "o") you can re-enter it by
appending a "#" at any input line. Then use "<",">" to navigate. You can change
individual tags by entering the corresponding _lowercase_ letter.
When a tag is set to [ask] or [regexp], enter "-" to clear this tag or "" if
you don't want to change this tag.
"""

next=1
first_loop=1
## I use a Pointer to the next arg - this is needed for <,> navigation
while next < len(argv):
  now=next
  if first_loop:
    next=now
    menu=1
    first_loop=0
  else:
    next=now+1
    print
    print argv[now]
    menu=0
    for j in attrib_keys: # ask for the tags we should ask for
      if menu:
        break
      attrib[j][ACT]=attrib[j][DEF]	# copy default to actual value
      if attrib[j][DEF]=="+":
        attrib[j][ACT]=read_check_len(attrib[j][DSC]+": ",j)
      elif attrib[j][DEF]=="*": # try to match regexp
        matched=regexp.match(argv[now])
        if matched:
          matched=matched.group(j)
          print attrib[j][DSC]+"="+matched
          tmp=read_check_len("change to: ",j)
          if tmp:
            attrib[j][ACT]=tmp
          else:
            attrib[j][ACT]=matched
        else:
          attrib[j][ACT]=read_check_len("[no match] "+attrib[j][DSC]+": ",j)

  if menu:
    command="x"
    while lower(command[0]) != "o":
      print
      print
      if next < len(argv):
        print '[x] next file is "'+argv[next]+'"'
      else:
        print '[x] exit after this one.'
      print '[x] actual file is "'+argv[now]+'"'
      print_changes()
      print
      print_defaults()
      command=(raw_input("(<>) (O)k (T)itle (A)rtist A(L)bum (Y)ear (C)omment (G)enre (E)dir re: ")+"x")[0]

      if command in all_tags:
        attrib[command][ACT]=read_check_len("Enter "+attrib[command][DSC]+" for this track: ",command)

      elif command in upper(all_tags):
        command=lower(command)
        print "Enter new default "+attrib[command][DSC]+" or [+] ask [*] re [-] clear [] no default: "
        attrib[command][DEF]=read_check_len("",command)

      elif command=="r":
        my_system("mp3info",("mp3info","-F2",argv[now]))

      elif command=="e":
        print "regexp="+regexp.pattern
        tmp=raw_input("change to: ")
        if tmp:
          regexp=compile(tmp)

      next=next+(command==">")-(command=="<")
      next=next+(next==0)

  cmd=["mp3info"]
  for j in attrib_keys:
    if attrib[j][ACT]:
      cmd.append(attrib[j][CMD])
      if attrib[j][ACT]=="-":			# "-" is special, it means
        cmd.append(" ")				# this tag will be cleared.
						# the " " is displayed but
						# the tag will empty (as tags
						# are initialized to " "s).
						# bug in mp3info?
      else:
        cmd.append(attrib[j][ACT])
  if len(cmd) > 1:
    cmd.append(argv[now])
    my_system("mp3info",cmd)
  else:
    print "nothing specified, nothing done."
else:
  if len(argv)<=1:
    print "noting to do."
