#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys, time
import glob
import codecs
import subprocess
import threading,thread
from multiprocessing import Process, Lock, Pipe
import re

#-----------------------------------------------------------
# global commons
#-----------------------------------------------------------
gs_debug=0
gs_verbose=0
gs_ff_loglev="verbose"
gs_ff_loglev="fatal"

gs_encode_sys="cp932" 		# default encode type of my system(os) : can get auto?
gs_timeup_geturl   =18.0
gs_timeup_getinfo  =30.0   # normal wait
gs_timeup_getinfo_l=40.0   # long wait for slow connection sites like nicovideo

#---- prog paths
gs_ffprobe="win32/ffprobe.exe"
gs_python=sys.executable	# path of python.exe
gs_prog_ytdl=[gs_python,"win32/youtube-dl/__main__.py"] 
gs_prog_ytdl=["win32\youtube-dl.exe"]    # / cause error, when shell exec
gs_prog_ytdl_s=" ".join(gs_prog_ytdl)

gs_python3="win32/Streamlink/Python/python.exe"
gs_prog_streamer=["win32/Streamlink/bin/streamlink.exe"]  # not-good: remain proc unkilled
gs_prog_streamer=[gs_python3,"win32/Streamlink/bin/streamlink-script.py"]
gs_prog_streamer_s=" ".join(gs_prog_streamer)
gs_streamer_conf="win32/Streamlink/conf/streamlinkrc.txt"


def setdbg (lv):
	global gs_debug
	
def dbg(*arg):
	global gs_debug
	if(gs_debug>0):
		#pass
		dbg0(*arg)

def dbg2(*arg):
	global gs_debug
	if(gs_debug>1):
		dbg0(*arg)

def dbg0(*arg):
	global gs_debug
	str=''.join(arg)
	print >>sys.stderr, str
	sys.stderr.flush()

def error(disp,*arg):
	str=''.join(arg)
	print >>sys.stderr, "[ERROR]: "+str
	
def isImage (path):
	lf=path.lower()
	if(lf.endswith((".jpg",".jpeg",".png",".bmp",".gif"))):
		return True
	else:
		return False

def isAudio (path):
	lf=path.lower()
	if(lf.endswith((".mp3",".m4a",".wma",".aac"))):
		return True
	return False

def isVideo (path):
	lf=path.lower()
	if(lf.endswith((".mp4",".ts",".m2ts",".mpg",".flv",".divx",".avi",".wmv"))):
		return True
	return False

def isWebVideo (path):
	# https://www.youtube.com/watch?v=6MyjFHd04R8
	# http://www.nicovideo.jp/watch/sm29155479

	if("www.youtube.com/watch" in path):
		return True
	elif("www.nicovideo.jp/watch" in path):
		return True
	else:
		return False

def isWebContents(path):
	if(re.match("^http[s]?://",path)):
		return True
	elif(re.match("^mms[ht]?://",path)):
		return True
	elif(re.match("^rtmp://",path)):
		return True
	else:
		return False

def isWebContents_old(path):
	if(path.startswith("http")):
		return True
	elif(path.startswith("mms")):
		return True
	elif(path.startswith("rtmp")):
		return True
	else:
		return False

# judge encode of input data and return encode, data(converted to unicode)
def conv_encoding (data):
    lookup = ('utf_8', 'cp932', 'euc_jp', 'euc_jis_2004', 'euc_jisx0213',
            'shift_jis', 'shift_jis_2004','shift_jisx0213',
            'iso2022jp', 'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_3',
            'iso2022_jp_ext','latin_1', 'ascii')
    encode = None
    for encoding in lookup:
      try:
        data = data.decode(encoding)
        encode = encoding
        break
      except:
        pass
    if isinstance(data, unicode):
        return data,encode
    else:
        raise LookupError

#-----------------------------------------------------------------
def gs_watchdog_timer (tim,pid):
	#global g_error
	
	if(gs_debug>0): dbg("gs_watchdog_timer: start timer=%f" % tim)
	try:
		time.sleep(tim)
		if(gs_debug>1): dbg("gs_watchdog_timer: Sleep Ended, interrupt")
		#g_error=1
		os.kill(pid,4)
	except RuntimeError,e:
		if(gs_debug>1): dbg("gs_watchdog_timer :RuntimeError, pass")
		pass
	except:
		if(gs_debug>1): dbg("gs_watchdog_timer :Unknown Error, pass")
		
	if(gs_debug>0): dbg("gs_watchdog_timer: end")

def gs_watchdog_pipe (pc,ppid,pid):
	import time
	# this mechanism work well, to know the parent death
	if(gs_debug>0): dbg("===== watchdog: started, mypid=%d ppid=%d pid=%d" % (os.getpid(),ppid,pid))
	
	time1=time.time()
	
	try:
		#read pipe in blocking mode
		#i.e. wait untill parent die, b/c parent never send to the pipe
		pc.recv()
		#good end (some data send from parent)
		os._exit(0)
	except EOFError:
		if(gs_debug>1): dbg("===== watchdog: EOFError on pipe.recv")
		#parent seems to be killed
		pass	#Noop
	except IOError:
		if(gs_debug>1): dbg("===== watchdog: IOError on pipe.recv")
		pass	#Noop
	
	if(gs_debug>1): dbg("===== watchdog: kill ppid=%d, pid=%d" % (ppid,pid))
	try:
		#os.kill(pid,signal.SIGKILL)
		os.kill(pid,9)
		#os.kill(ppid,9)
	except WindowsError:
		if(gs_debug>1): dbg("WindowsError: pid=%d may not exists" % pid)

	time2=time.time()
	time=time2-time1
	if(gs_debug>0): dbg("watchdog: end, play time=%f" % time)
	
	#sys.exit()
	os._exit(0)

def gs_exec_prog_get (mode,args,elogf,tm,wait):
	outbuf=[]
	if(gs_debug>0): dbg("exec_prog_get: mode=%d, wait=%d, elogf=%s, args=%s" % (mode,wait,elogf,args))
	try:
		cwd="./"
		if(mode==1):
			p = subprocess.Popen(args, shell=False, cwd=cwd, stdin=None,
		    	stdout=subprocess.PIPE, stderr=elogf,
		    	close_fds=False)
		elif(mode==2):
			p = subprocess.Popen(args, shell=False, cwd=cwd, stdin=None,
		    	stdout=elogf, stderr=subprocess.PIPE,
		    	close_fds=False)
		else:
			p = subprocess.Popen(args, shell=False, cwd=cwd, stdin=None,
		    	stdout=None, stderr=None,
		    	close_fds=False)
		 	
	except OSError:
		dbg("Failed to exec %s" % args)
		return (1,outbuf)

	#---- watchdog_pipe: kill child when parant died
	#pp,pc=Pipe()
	#Process(target=gs_watchdog_pipe,args=(pc,os.getpid(),p.pid)).start()
	
	#---- watchdog_timer: kill child when timeup
	if(gs_debug>1): dbg("gs_exec_prog_get: gs_watchdog_timer, start")
	if(tm>0):	#timeup time
		p2=Process(target=gs_watchdog_timer,args=(tm,p.pid))
		p2.start()
	if(wait==False):
		return
	if(mode==1):
		(sto)=(p.stdout)
	else:
		(sto)=(p.stderr)
	
	if(gs_debug>1): dbg("gs_exec_prog_get: read output from proc, start")
	while True:
		line=sto.readline()
		if not line:
			break
		outbuf.append(line)
		#dbg(line)
	
	if(gs_debug>1): dbg("gs_exec_prog_get: wait proc start")
	ret=p.wait()
	if(gs_debug>1): dbg("gs_exec_prog_get: wait proc end rc=%r" % ret)
	if(tm>0):
		try:
			p2.terminate()
		except WindowsError:
			pass
	if(gs_debug>0): dbg("gs_exec_prog_get: return rc=%r" % ret)
	return (ret,outbuf)

def gs_get_minfo_fp(url):
	dbg("gs_get_minfo_fp: start url=%s" % (url))

	#------------------------------------------------------------
	# get media profile (size,fps) using ffprobe
	#------------------------------------------------------------
	#---- set defaults
	asp=0.0
	#for test
	w=1280.0
	h=720.0
	fps=29.970
	ac="-"	#acodec
	abps=0
	ach=0
	vc="-"	#vcodec
	vlev=0
	fmt="-"	#format
	fp_opt=""
	level="high"
	rc=-1
	
	#return (rc,fmt,ac,abps,ach)
	
	args=gs_ffprobe+" -show_format -show_streams "+fp_opt+url
	args=args.split()
	if(level == "best"):
		#dash video is terrible slow?
		#timeup=30.0	# timelimit for wait child ends
		timeup=gs_timeup_getinfo_l	# timelimit for wait child ends
	else:
		#timeup=15.0	# timelimit for wait child ends
		timeup=gs_timeup_getinfo	# timelimit for wait child ends
	#(rc,outbuf)=gs_exec_prog_get(1,args,sys.stderr,timeup,True)
	(rc,outbuf)=gs_exec_prog_get(1,args,None,timeup,True)
		
	dbg("get_minfo: ffprobe rc=%d, outbuf_lines=%d" % (rc,len(outbuf)))
	dbg("args=%s" % (args))
	
	if(gs_verbose>0):
		dbg("------ ffprobe outputs start -------------")
		dbg("OUT=%s" % outbuf)
		dbg("OUT END-------------------------------------")

	pos=0
	state=0			# chunk type  =1:stream,=2:format
	stream_type=0   # stream type =1:video ,=2:audio
	stream_v=0 		# video stream number (valid from 1)
	stream_a=0		# audio stream number (valid from 1)
	if(len(outbuf)>0):
		for i in range(len(outbuf)):
			str=outbuf[i].strip()
			if(gs_debug>1): dbg("get_minfo_fp: line[%d]=%s" % (i,str))
			
			#---- chunks
			pos=str.find("[STREAM]")
			if(pos==0):
				dbg("found [STREAM]")
				state=1
				stream_type=0 			# reset to unknown
				codec_name="unknown"	# reset to unknown
				
			pos=str.find("[/STREAM]")
			if(pos==0):
				dbg("found [/STREAM]")
				if(stream_v==1):
					pass
					#break	#video found
			pos=str.find("[FORMAT]")
			if(pos==0):
				state=2
			
			#---- stream
			if(state==1):	#[STREAM]
				pos=str.find("codec_name=")
				#if(pos==0 and vc=="-"): #not setted yet
				if(pos==0):
					#stream type is yet unknown : "codec_name" appears before "codec_type" !!
					codec_name=str[pos+len("codec_name="):]
				pos=str.find("codec_type=")
				if(pos==0):
					str=str[pos+len("codec_type="):]
					dbg("found codec_type=%s" % (str))
					if("video" in str):
						stream_type=1
						stream_v+=1
						vc=codec_name
					elif("audio" in str):
						stream_type=2
						stream_a+=1
						ac=codec_name
			#---- video stream
			if(state==1 and stream_type==1 and stream_v==1): #video stream 1st
				pos=str.find("level=")
				if(pos==0):
					vlev=int(str[pos+6:])
					dbg("vlevel=%d" % (vlev))
				pos=str.find("width=")
				if(pos==0):
					str=str[pos+6:]
					w=float(str)
				pos=str.find("height=")
				if(pos==0):
					str=str[pos+7:]
					h=float(str)
					
				pos=str.find("level=")
				if(pos==0):
					str=str[pos+6:]
					vlev=int(str)
					
				pos=str.find("r_frame_rate=")
				if(pos==0):
					str=str[pos+13:]
					ar=str.split("/")
					if(len(ar)>1):
						fps=float(ar[0])/float(ar[1])
					
				pos=str.find("display_aspect_ratio=")
				if(pos==0):
					str=str[pos+len("display_aspect_ratio="):]
					ar=str.split(":")
					if(len(ar)>1):
						asp=float(ar[0])/float(ar[1])
			
			#---- audio stream
			elif (state==1 and stream_type==2 and stream_a==1): #audio stream 1st 
				pos=str.find("bit_rate=")
				if(pos==0):
					abps=int(str[pos+len("bit_rate="):])
					dbg("gs_get_minfo_fp: abps=%d" % (abps))
				pos=str.find("channels=")
				if(pos==0):
					ach=int(str[pos+len("channels="):])
					dbg("gs_get_minfo_fp: ach=%d" % (ach))
				
			#---- format
			elif (state==2): #[FORMAT]
				pos=str.find("format_name=")
				if(pos==0):
					str=str[pos+len("format_name="):]
					mv=str.split(",")
					#dbg("get_minfo_fp: found format_name=%s mv=%r" % (str,mv))
					if(len(mv)>0):
						fmt=mv[0]
					if(fmt=="mov"):
						fmt="mp4"
				
				pos=str.find("TAG:StreamTitle=")
				if(pos==0):
					stitle=str[pos+len("TAG:StreamTitle="):]
					dbg("gs_get_minfo_fp: Stream Title=%s" % (stitle))
				#pass

	#dbg("gs_get_minfo_fp: parse loop end")
	
	if(fmt=="-"):
		rc= -1
	dbg("gs_get_minfo_fp: end rc=%d, fmt=%s, vc=%s, ac=%s, abps=%d, ach=%d" % (rc,fmt,vc,ac,abps,ach))
	return (rc,fmt,ac,abps,ach)
	#return (rc,fmt,w,h,fps,vc,vlev,asp)

