#!/usr/bin/env python

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

	# TODO: support wav joining	
	

""" usage: audiojoin.py [options]
		  Note: mp3 and wav files are the only supported
		  sources.
		  
    -d  work with the provided directory
        [default: the current working directory]
	 -f  force join, even though file discrepencies exist
    -h  this help
    -j  joins files together
    -i  prints out information about files (mp3)
    -r  recursive file lookup
    -s  statistic summary of information about files (mp3) 
	 -w  source files are wav [default: mp3]

    Written by Ari Bjornsson ari.bjornsson (at) gmail.com
"""

import sys
import os
import getopt
import subprocess
import string

def usage(*args):
    sys.stdout = sys.stderr
    print __doc__
    print 50*"-"
    for msg in args: print msg
    sys.exit(2)
    
def unix_path(type,path):
	if type == 'd': 
		if path[-1] != '/': path += '/'

	path = path.replace(' ','\ ')
	path = path.replace("'","\\'")
	path = path.replace("(","\\(")
	path = path.replace(")","\\)")
	path = path.replace("{","\\{")
	path = path.replace("}","\\}")
	path = path.replace('&','\&')	

	return path
	    
def fileList(type, workingDir = '', recursive = False):
	file_list = []	
	if recursive:
		walk = os.walk(workingDir, topdown=True)
		for root, dirs, files in walk:		        		
			for name in files:
				if os.path.splitext(name)[1].lower() == type:
					file_list.append(os.path.join(root,name))
	else:
		walk = os.walk(workingDir, topdown=True)	        		
		cnt = 0
		for root, dirs, files in walk:		
			for name in files:
				if os.path.splitext(name)[1].lower() == type:
					file_list.append(os.path.join(root,name))
			cnt += 1
			if cnt >= 1:
				break
					  
	file_list.sort()
	
	return file_list

def retrieveInfo(type, workingDir, recursive):
	file_list = fileList(type, workingDir, recursive)	
	meta = []
	for file in file_list:
		p = subprocess.Popen(["mp3check", "-c", file], stdout=subprocess.PIPE)
		output = p.communicate()
		line = str(output[0])
		attr = [file]

		for item in line.split(' '):
			if item != '':
				attr.append(item)		
		
		if len(attr) > 8:
			del attr[8:len(attr)]
		elif len(attr) < 8:
			del attr[1:len(attr)]
			attr.append('Information not available')		

		# attr: file_name audio_layer sampling_rate bit_rate	channels n/a n/a duration		
		meta.append(attr)
		
	return meta		

def summaryInfo(type,workingDir, recursive):
	info = retrieveInfo(type, workingDir, recursive)
	# Audio Layer: distinct type, count
	# Sampling Rate: distinct rate, count
	# Bitrate: distinct rate, count
	# Channels: distinct type, count
	# Missing Info: total missing, total files
	summary = {'Audio Layer':[], 'Sampling Rate':[], 'Bitrate':[], 'Channels':[], 'Missing Info':[]}

	cnt = 1
	for item in summary:
		type = ''
		types = []
		each_type_cnt = 0
		each_type = []
		
		if cnt in [1,2,3,4]:
			for attr in info:
				if len(attr) > 2:
					if type == '' or type != attr[cnt]:
						type = attr[cnt]
					
						x = 0
						for t in types:
							if t == type:
								x += 1
							
						if x == 0:
							types.append(attr[cnt])
			
			for type in types:
				d = 0			
				for attr in info:
					if len(attr) > 2:
						if type == attr[cnt]:
							d += 1
				each_type.append(d)					
								
		if cnt == 1:		
			summary['Audio Layer'].append(types)
			summary['Audio Layer'].append(each_type)
		if cnt == 2:
			summary['Sampling Rate'].append(types)
			summary['Sampling Rate'].append(each_type)
		if cnt == 3:
			summary['Bitrate'].append(types)
			summary['Bitrate'].append(each_type)
		if cnt == 4:
			summary['Channels'].append(types)
			summary['Channels'].append(each_type)							
		if cnt == 5:
			y = 0
			z = 0
			for attr in info:
				if attr[1] == 'Information not available':		
					y += 1
				z += 1
				
			summary['Missing Info'].append(y)
			summary['Missing Info'].append(z)
			
		cnt += 1

	# print out summary
	layers = summary['Audio Layer'][0]
	lay_number = summary['Audio Layer'][1]	
	sampling = summary['Sampling Rate'][0]
	samp_number = summary['Sampling Rate'][1]
	bitrate = summary['Bitrate'][0]
	bit_number = summary['Bitrate'][1]
	channels = summary['Channels'][0]
	cha_number = summary['Channels'][1]

	
	total_info_files = summary['Missing Info'][1] - summary['Missing Info'][0]
	total_files = summary['Missing Info'][1]

	#print "\n"
	print 7*"*" + " Statistical Summary " + 7*"*"
	#print "\n"
	print "Audio Layer:\t",
	v = 0	
	for layer in layers:
		print layer + "(" + str(lay_number[v]) + "/" + str(total_info_files) + ") ",		
		v += 1 		
	print "\nSampling Rate:\t",
	k = 0
	for rate in sampling:	
		print rate + "(" + str(samp_number[k]) + "/" + str(total_info_files) + ") ",
		k += 1	
	print "\nBitrate:\t",
	b = 0
	for rate in bitrate:	
		print rate + "(" + str(bit_number[b]) + "/" + str(total_info_files) + ") ",
		b += 1	
	print "\nChannels:\t",
	c = 0
	for cha in channels:	
		print cha + "(" + str(cha_number[c]) + "/" + str(total_info_files) + ") ",
		c += 1
	
	print "\n\nInfo missing:\t" + str(summary['Missing Info'][0]) + " of " +	str(summary['Missing Info'][1]) + " files\n"
	
	return summary	
			
def printInfo(type, workingDir, recursive):
	info = retrieveInfo(type,workingDir,recursive)
	
	if len(info) > 0:
		for i in info:
			if len(i) <= 2:			
				print 5*'-' + ' ' + i[0] + ' ' + 5*'-'				
			else:
				print 5*'-' + ' ' + i[0] + ' ' + 5*'-'
				print 'Audio Layer:\t' + i[1]
				print 'Sampling Rate:\t' + i[2] + ' kHz'
				print 'Bitrate:\t' + i[3] + ' kbps'
				print 'Channels:\t' + i[4]
				print 'Duration:\t' + i[7]			

	print "\nFor more detailed information try:\n\t#: mp3check -l filename\n"
	
def discrepency(type, workingDir, recursive):
	summary = summaryInfo(type, workingDir, recursive)
	
	if len(summary['Audio Layer'][0]) > 1 or len(summary['Sampling Rate'][0]) > 1 or len(summary['Bitrate'][0]) > 1 or len(summary['Channels'][0]) > 1:
		return True	
	else:
		return False

def tagFile(list, out_file):
	artist = ''
	album = ''
	year = ''

	# get tags from input files
	for file in list:
		t_command = "id3v2 -l " + unix_path('f',file)

		t = subprocess.Popen(t_command, shell=True, stdout=subprocess.PIPE)
		t.wait()
		output = t.communicate()
		info = output[0].split('\n') 
	
		cnt = 1
		if info[1] != '':
			for i in info:
				attr = i.split(':')
				if len(attr) > 1:
					key = attr[0][0:4]
					value = attr[1]
					if value != '':
						if value[0] == ' ':
							value = value[1:]
					if key == 'TPE1' and artist == '':
						artist = value
					if key == 'TALB' and album == '':
						album = value
					if key == 'TYER' and year == '':
						year = value
	
	comment = 'This audio file was joined by audiojoin - a script created by Ari Bjornsson, ari.bjornsson (at) gmail.com'	
	track = '01'

	s = out_file.split('/')
	song = s[len(s)-1][:-4]

	# clear current tags		
	c_command = 'id3v2 -D ' + unix_path('f',out_file)
	subprocess.Popen(c_command, shell=True, stdout=subprocess.PIPE)

	# assign new tags
	a_command = 'id3v2 -a ' + "\'" + artist + "\'" + ' -A ' + "\'" + album + "\'" + ' -t ' + "\'" + song + "\'" + ' -c ' + "\'" + comment + "\'" + ' -y ' + "\'" + year + "\'" + ' -T ' + "\'" + track + "\'" + ' ' + unix_path('f',out_file)
	subprocess.Popen(a_command, shell=True, stdout=subprocess.PIPE)
	
def joinFiles(type, workingDir = "", recursive=False):	
	list = fileList(type, workingDir, recursive)
	
	line = ''
	for file in list:
		line = line + unix_path('f',file) + ' '		
	
	if type == '.mp3':
		command = "mpgtx -j " + line + " -o " + unix_path('d',workingDir) + "tmp_MP3WRAP.mp3"				
	if type == '.wav':
		pass	
	
		
	print "Joining files, please wait .."		
	p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
	p.wait()		
	output = p.communicate()		

	if os.path.isfile(workingDir + 'tmp_MP3WRAP.mp3'):
		# file name as directory name
		if workingDir[-1] == "/":
				tmp_workingDir = workingDir[:-1]
		else:
				tmp_workingDir = workingDir
				
		dirs = tmp_workingDir.split('/')
		dir = dirs[len(dirs)-1]
	
		if type == '.mp3':
			os.rename(workingDir + 'tmp_MP3WRAP.mp3',workingDir + dir + '.mp3')
			tagFile(list,workingDir + dir + '.mp3') 
		else:
			pass	
	
		print "Done."
	else:
		print "Warning: script did not output any file"	
# Main program: parse command line and start processing
def main():
	try:
		opts, args = getopt.getopt(sys.argv[1:], 'd:fijrsw')
	except getopt.error, msg:
		usage(msg)

	workingDir = os.getcwd()
	type = '.mp3'
	recursive = False
	info = False
	summary = False
	encode = False
	force = False

#	overwriteM4bs = False
#	removeSources = False
#	Source = '.mp3'


	for o, a in opts:
		if o == '-h':
			print __doc__
			sys.exit()
		if o == '-d':
			if os.path.isdir(a):
				workingDir = a
			else:
				print "Error: The provided path is no directory"
				sys.exit()   				
		if o == '-r':
			recursive = True		
		if o == '-i':
			info = True
		if o == '-s':
			summary = True
		if o == '-w':
			type = '.wav'	
		if o == '-f':
			force = True
				
	if workingDir[-1] != "/":
			workingDir += "/"	
	
	if info:		
		printInfo(type, workingDir, recursive)
		return
	if summary:
		summaryInfo(type, workingDir, recursive)
		return			
	
	disc = discrepency(type, workingDir, recursive)	
	if disc and not force:
		print 'File discrepency found, halting script. Try -f flag to ignore'
	else:
		joinFiles(type, workingDir, recursive)		
        
if __name__ == '__main__':
	main()

