#!/usr/local/bin/python
from MythTV import MythTV, MythDB, MythLog, MythVideo, Program, FileTransfer, Job, NOTICE, INFO, DEBUG
from socket import gethostname
from urllib import urlretrieve
import sys, getopt, re, os, time#, pprint

#Usage: mythvidexport.py <--chanid <channel id>> <--starttime <start time>> [options]
#		--fformat <see directory/file name options>
#		--tformat <see directory/file name options>
#	moves a single file over to MythVideo with optional directory format, format is discarded after use

#Usage: mythvidexport.py <job id>
#		WARNING: for internal use by job queue only!
#	moves a single file, grabbing necessary information from job queue table

#Usage: mythvidexport.py <options>
#		--setformat <see directory/file name options>
#			stored directory format in database for future use
#		--help
#		--helpformat
#			lengthy discription of directory formatting
#		--delete

log = MythLog(NOTICE, 'MythVidExport.py')

class VIDEO:
	mythdb = None
	dbconn = None
	job = None
	jobhost = None
	chanid = None
	rtime = None

	prog = None
	source = None
	srchost = None
	dest = None
	desthost = None

	ttvdb = None
	ffmt = None
	dfmt = None
 
	viddata = {}
	cast = []
	genre = []
	country = []

	def __init__(self, *inp):
		if len(inp) == 1:
			self.job = Job(inp[0]);
			self.chanid = self.job.chanid
			self.rtime = "%04d%02d%02d%02d%02d%02d" % self.job.starttime.timetuple()[0:6]
			self.jobhost = self.job.host
			self.job.setStatus(3)
		elif len(inp) == 2:
			self.chanid = inp[0]
			self.rtime = inp[1]
		else:
			sys.exit(2)
		self.get_source()

	def dbconnect(self):
		self.mythdb = MythDB()
		self.dbconn = self.mythdb.db

	def get_source(self):
		## connects to myth data socket and finds recording
		if not self.dbconn:
			self.dbconnect()
		if not self.jobhost:
			self.jobhost = gethostname()

		mythinst = MythTV()
		self.prog = mythinst.getRecording(self.chanid,int(self.rtime))

		self.srchost = self.prog.hostname
		self.source = mythinst.getCheckfile(self.prog)

	def find_ttvdb(self):
		## searches for ttvdb.py script, and optional config file
		if os.access('/usr/local/share/mythtv/mythvideo/scripts/ttvdb.py',os.F_OK):
			self.ttvdb = '/usr/local/share/mythtv/mythvideo/scripts/ttvdb.py'
		elif os.access('/usr/share/mythtv/mythvideo/scripts/ttvdb.py',os.F_OK):
			self.ttvdb = '/usr/local/share/mythtv/mythvideo/scripts/ttvdb.py'
		else:
			log.critical('Dependancy error', "Could not find ttvdb.py")
			self.exit(2)
		if os.access(os.path.expanduser("~/.mythtv/ttvdb.conf"),os.F_OK):
			self.ttvdb += ' -c ' + os.path.expanduser("~/.mythtv/ttvdb.conf")
		log.info("using '%s'" % self.ttvdb)

	def get_meta(self):
		## grab season and episode number from thetvdb.com, exit if failed
		regex = re.compile('S(?P<season>[0-9]*)E(?P<episode>[0-9]*)')
		match = None
		if self.ttvdb == None:
			self.find_ttvdb()
		fp = os.popen("%s -N \"%s\" \"%s\"" % (self.ttvdb,self.prog.title,self.prog.subtitle),"r")
		match = regex.search(fp.read())
		fp.close()
		if match is None:
			log.warning('Grabber error', "TTVDB.py failed to get season/episode numbers for %s - %s" % (self.prog.title, self.prog.subtitle))
			if self.job:
				self.job.setComment("TTVDB.py failed to get season/episode numbers")
				self.job.setStatus(304)
			sys.exit(2)

		self.viddata['season'] = int(match.group('season'))
		self.viddata['episode'] = int(match.group('episode'))

		## gather remaining data
		fp = os.popen("%s -mD '%s' %d %d" % (self.ttvdb,self.prog.title,self.viddata['season'],self.viddata['episode']))
		time.sleep(2)
		res = fp.read()
		fp.close()
		if len(res) == 0:
			## ttvdb failed to grab data, use listings information
			self.viddata['director'] = self.mythdb.getCast(self.chanid, int(self.rtime), roles='director')
			if len(self.viddata['director']) == 0:
				self.viddata['director'] = 'NULL'
			else:
				self.viddata['director'] = self.viddata['director'][0]
			self.viddata['title'] = self.prog.title
			self.viddata['subtitle'] = self.prog.subtitle
			self.viddata['plot'] = self.prog.description
			self.viddata['year'] = self.prog.year
			self.viddata['length'] = str(int((self.prog.recendts-self.prog.recstartts).seconds/60))
			self.cast = self.mythdb.getCast(self.chanid, int(self.rtime), roles=('actor','guest_star','host','commentator','guest'))
			self.viddata['inetref'] = '00000000'
			self.genre = ()
			self.country = ()
		else:
			ttvdbdat = {}
			for point in res.split('\n')[:-1]:
				key,dat = point.split(':',1)
				ttvdbdat[key] = dat
			self.viddata['title'] = self.prog.title
			self.viddata['subtitle'] = ttvdbdat['Subtitle']
			self.viddata['director'] = ttvdbdat['Director']
			self.viddata['plot'] = ttvdbdat['Plot']
			self.viddata['year'] = ttvdbdat['Year']
			self.viddata['length'] = ttvdbdat['Runtime']
			self.viddata['userrating'] = ttvdbdat['UserRating']
			self.cast = tuple(ttvdbdat['Cast'].split(', '))
			self.genre = tuple(ttvdbdat['Genres'].split(', '))
			self.viddata['inetref'] = ttvdbdat['Seriesid']
			self.country = ()

		self.viddata['showlevel'] = 1
		self.viddata['rating'] = 'NR'
		self.viddata['coverfile'] = 'No Cover'

	def get_dest(self):
		if self.ffmt is None:
			self.get_fmt()
		ext = self.source[self.source.rfind('.'):]
		subpath = self.process_fmt(self.dfmt) + "/" + self.process_fmt(self.ffmt) + ext

		self.desthost = self.jobhost
		cursor = self.dbconn.cursor()
		reslen = cursor.execute("SELECT dirname FROM storagegroup WHERE hostname='%s' and groupname='Videos'" % self.desthost)
		if reslen:
			destdir = cursor.fetchone()[0]
			self.destdb = subpath
		else:
			destdir = self.mythdb.getSetting("VideoStartupDir",hostname=self.jobhost)+'/'
			self.destdb = self.dest
		self.dest = destdir+subpath

		tmppath = self.dest[0:self.dest.rfind('/')] 
		if not os.access(tmppath,os.F_OK):
			os.makedirs(tmppath)

	def set_dfmt(self, fmt):
		self.dfmt = fmt
	def set_ffmt(self, fmt):
		self.ffmt = fmt

	def get_fmt(self):
		self.ffmt = self.mythdb.getSetting('TV Export File Format')
		if not self.ffmt:
			self.ffmt = '%TITLE% - %SEASON%x%EPISODEPAD% - %SUBTITLE%'
		self.dfmt = self.mythdb.getSetting('TV Export Directory Format')
		if not self.dfmt:
			self.dfmt = 'Television/%TITLE%'

	def process_fmt(self, fmt):
		fmt = fmt.replace('%TITLE%',self.viddata['title'])
		fmt = fmt.replace('%SUBTITLE%',self.viddata['subtitle'])
		fmt = fmt.replace('%SEASON%',"%d" % self.viddata['season'])
		fmt = fmt.replace('%SEASONPAD%',"%02d" % self.viddata['season'])
		fmt = fmt.replace('%EPISODE%',"%d" % self.viddata['episode'])
		fmt = fmt.replace('%EPISODEPAD%',"%02d" % self.viddata['episode'])
		fmt = fmt.replace('%YEAR%',self.viddata['year'])
		fmt = fmt.replace('%DIRECTOR%',self.viddata['director'])
#		fmt = fmt.replace('%CARDID%',self.prog.cardid)
#		fmt = fmt.replace('%CARDNAME%',self.prog.cardid)
#		fmt = fmt.replace('%SOURCEID%',self.prog.cardid)
#		fmt = fmt.replace('%SOURCENAME%',self.prog.cardid)
		fmt = fmt.replace('%HOSTNAME%',self.prog.hostname)
		fmt = fmt.replace('%STORAGEGROUP%',self.prog.storagegroup)
#		fmt = fmt.replace('%CHANNUM%',self.prog.channum)
#		fmt = fmt.replace('%CHANNAME%',self.prog.cardid)
		if len(self.genre):
			fmt = fmt.replace('%GENRE%',self.genre[0])
		else:
			fmt = fmt.replace('%GENRE%','')
#		if len(self.country):
#			fmt = fmt.replace('%COUNTRY%',self.country[0])
#		else:
#			fmt = fmt.replace('%COUNTRY%','')
		return fmt

	def copy(self):
		cursor = None
		srcp = None
		srcsize = None
		dtime = None
		self.get_meta()
		self.get_dest()
		if self.desthost != self.jobhost:
			log.warning('failed','must be run on destination host')
			if self.job:
				self.job.setComment("Job must be run on destination host")
				self.job.setStatus(304)
			sys.exit(2)

		log.notice('Starting transfer','from %s:%s to %s' % (self.srchost,self.source,self.dest))
		stime = time.time()
		ctime = time.time()
		if os.access(self.source,os.F_OK):
			srcp = open(self.source,'r')
		else:
			srcp = FileTransfer(self.prop)
		destp = open(self.dest,'w')
		srcsize = self.prog.filesize
		destsize = [0,0,0,0,0,0,0,0,0,0]
		if self.job:
			self.job.setStatus(4)
		tsize = 2**18
		while tsize == 2**18:
			if (srcsize - destp.tell()) < tsize:
				tsize = srcsize - destp.tell()
			if time.time() - ctime > 4:
				ctime = time.time()
				destsize.append(destp.tell())
				rem = srcsize - destp.tell()
				if destsize[0]:
					dtime = 40
				else:
					dtime = int(ctime - stime)
				rate = (destp.tell() - destsize.pop(0))/dtime
				remt = rem/rate
				if self.job:
					self.job.setComment("%02d%% complete - %s seconds remaining" % (destsize[9]*100/srcsize, remt))
			destp.write(srcp.read(tsize))

		srcp.close()
		destp.close()
		log.notice('Transfer complete','%d seconds elapsed' % int(time.time()-stime))
		if self.job:
			self.job.setComment("Complete - %d seconds elapsed" % (int(time.time()-stime)))
			self.job.setStatus(256)


	def write_meta(self):
		mythvid = MythVideo()
		mythtv = MythTV()
#		pp = pprint.PrettyPrinter(indent=4)
		self.viddata['filename'] = self.destdb
		self.viddata['host'] = self.desthost


#		pp.pprint(self.viddata)
		intid = mythvid.getMetadataId(self.destdb)
		if intid:
			mythvid.setMetadata(self.viddata,intid)
		else:
			intid = mythvid.setMetadata(self.viddata)
#		print("Metadata written to intid %d" % intid)
#		pp.pprint(self.viddata)

#		print("With cast:")
#		pp.pprint(self.cast)
		for name in self.cast:
			mythvid.setCast(name, intid)
#		print("With genre:")
#		pp.pprint(self.genre)
#		for genre in self.genre:
#			mythvid.setGenre(genre, intid)
		self.write_image('coverfile',intid)
		self.write_image('banner',intid)
		self.write_image('fanart',intid)
		if self.job:
			self.job.setStatus(272)

	def write_image(self,mode,intid):
		destdir = None
		SG = {'coverfile':'Coverart','banner':'Banners','fanart':'Fanart'}
		ttvdb = {'coverfile':'-mP','banner':'-mB','fanart':'-mtF'}
		mythvid = MythVideo()
		cursor = self.dbconn.cursor()
		reslen = cursor.execute("SELECT dirname FROM storagegroup WHERE hostname='%s' and groupname='%s'" % (self.desthost,SG[mode]))
		if reslen:
			destdir = cursor.fetchone()[0]
		else:
			return

		fp = os.popen("%s %s '%s' %d %d" % (self.ttvdb,ttvdb[mode],self.prog.title,self.viddata['season'],self.viddata['episode']))
		time.sleep(2)
		res = fp.read()
		fp.close()

		match = re.match('http://images.thetvdb.com.nyud.net:8080/[a-zA-Z/]*/(?P<file>[a-zA-Z0-9-.]*)',res)
		if not match:
			return
		path = destdir+match.group('file')
		if not os.access(path,os.F_OK):
			urlretrieve(match.group(),path)
		if mode == 'coverfile':
			if not os.access(destdir+'folder.jpg',os.F_OK):
				urlretrieve(match.group(),destdir+'folder.jpg')

		mythvid.setMetadata({mode:match.group('file')},intid)

	def delete():
		mythtv = MythTV()
		mythtv.deleteRecording(self.prog)

def usage():
	print("mythvidexport.py [options] [--chanid=<chanid> --starttime=<starttime> | <jobid>]")
	print("        This script can be run by specifing the channel and start time directly")
	print("            or by specifing the ID of a job in jobqueue")
	print("")
	print("        Run from the command line through the former:")
	print("            mythvidexport.py --chanid=1002 --starttime=200907010000")
        print("        Or from a user script through the latter:")
        print("            mythvidexport.py %JOBID%")
	print("")
	print("    Options:")
	print("        -h/--help and -f/--helpformat:")
	print("             return this help, or a listing of available formatting strings")
	print("        --fformat='<string>' and --dformat='<string>':")
	print("             override the stored formatting string in the database")
        print("             if no recording is specified, store format string to the database")

def usage_format():
	print("The default strings are:")
	print("    fformat: '%TITLE% - %SUBTITLE%'")
	print("    dformat: 'Television/%TITLE%'")
	print("")
	print("Available strings:")
	print("    %TITLE%:         series title")
	print("    %SUBTITLE%:      episode title")
	print("    %SEASON%:        season number")
	print("    %EPISODE%:       episode number, padded to 2 digits")
	print("    %YEAR%:          year")
	print("    %DIRECTOR%:      director")
#	print("    %CARDID%:        ID of tuner card used to record show")
#	print("    %CARDNAME%:      name of tuner card used to record show")
#	print("    %SOURCEID%:      ID of video source used to record show")
#	print("    %SOURCENAME%:    name of video source used to record show")
        print("    %HOSTNAME%:      backend used to record show")
	print("    %STORAGEGROUP%:  storage group containing recorded show")
#	print("    %CHANNUM%:       ID of channel used to record show")
#	print("    %CHANNAME%:      name of channel used to record show")
	print("    %GENRE%:         first genre listed for recording")
#	print("    %COUNTRY%:       first country listed for recording")

def main():
	fformat = None
	tformat = None
	jobid = None
	chanid = None
	rtime = None
	skip = False
	delete = False
	try:
		opts, args = getopt.getopt(sys.argv[1:], "hf", ["help","helpformat","fformat=","dformat=","chanid=","starttime=","skip","delete"])
	except getopt.GetoptError, err:
		print(str(err))
		usage()
		sys.exit(2)
	for opt, arg in opts:
		if opt in ("-h", "--help"):
			usage()
			sys.exit()
		elif opt in ('-f', '--helpformat'):
			usage_format()
			sys.exit()
		elif opt == '--dformat':
			dformat = arg
		elif opt == '--fformat':
			fformat = arg
		elif opt == '--chanid':
			chanid = int(arg)
		elif opt == '--starttime':
			rtime = int(arg)
		elif opt == '--skip':
			skip = True
		elif opt == '--delete':
			delete = True
		
	if len(args):
		jobid = int(args[0])

	if chanid and rtime:
		export = VIDEO(chanid,rtime)
	elif jobid:
		export = VIDEO(jobid)
	elif fformat or dformat:
		if fformat:
			mythdb = MythDB()
			mythdb.setSetting('TV Export File Format', fmt)
		if dformat:
			mythdb = MythDB()
			mythdb.setSetting('TV Export Directory Format', fmt)
		sys.exit()
	else:
		usage()
		sys.exit(2)

	if skip:
		export.get_meta()
		export.get_dest()
	else:
		export.copy()
	export.write_meta()
#	if delete:
#		export.delete()

if __name__ == "__main__":
	main()

