

from autosub import DEFAULT_CONCURRENCY
from autosub import DEFAULT_SUBTITLE_FORMAT
from pytranscriber.control.ctr_main import Ctr_Main
from pytranscriber.control.ctr_autosub import Ctr_Autosub
import re,random, time
from itertools import groupby
from operator import itemgetter
from rakeUtil.Rake import Rake
import requests,rpyc
from difflib import SequenceMatcher
from PIL import Image,ImageDraw,ImageFont
import openshot
obj = Rake()
stop_path = "rakedata/stoplist/中文停用词表(1208个).txt"
conj_path = "rakedata/stoplist/中文分隔词词库.txt"
obj.initializeFromPath(stop_path, conj_path)

def trim_punctuation(s):
    pat_block = u'[^\u4e00-\u9fff0-9a-zA-Z]+';
    pattern = u'([0-9]+{0}[0-9]+)|{0}'.format(pat_block)
    res = re.sub(pattern, lambda x: x.group(1) if x.group(1) else u" " ,s)
    return res

def txt2image(content, save_target,lang='zh'):
    unicode_text = trim_punctuation(content)
    content = content.replace(' ','')
    font = ''
    if lang=='zh':
        font = ImageFont.truetype(font="font/DFT_B7.ttc", size=38)
    else :
        font = ImageFont.truetype(font="font/arial.ttf", size=38)
    text_width, text_height = font.getsize(unicode_text)
    canvas = Image.new('RGBA', (700, 500), (255, 0, 0, 0) )
    draw = ImageDraw.Draw(canvas)
    text= unicode_text
    draw.text((5,5), text, (255, 255, 0), font)
    canvas.save(save_target, "PNG")

def generate_subtitle_image_from_dict(cpath, sub_dict):
    for script in sub_dict:
        sv_path = cpath + '/' + str(script['index'])+'.png'
        sub = script['content']
        txt2image(sub,sv_path)

def listener_progress(string, percent):
    True

def transScript(cpath):
    Ctr_Autosub.init()
    Ctr_Autosub.generate_subtitles(cpath+"speech.mp3",'zh'
    ,listener_progress
    ,output=cpath+"script.txt"
    ,concurrency=DEFAULT_CONCURRENCY,subtitle_file_format=DEFAULT_SUBTITLE_FORMAT)

def syllable_count(word):
    word = word.lower()
    count = 0
    vowels = "aeiouy"
    if word[0] in vowels:
        count += 1
    for index in range(1, len(word)):
        if word[index] in vowels and word[index - 1] not in vowels:
            count += 1

    if word.endswith("e"):
        count -= 1
    if count == 0:
        count += 1
    return count

def getKeyword(inStr):
    re.findall(r'[\u4e00-\u9fff]+', inStr)

    zh_idx = []
    eng_idx= []
    for i in range(len(inStr)):
        if inStr[i] > u'\u4e00' and inStr[i] < u'\u9fff':
            zh_idx.append(i)
        else:
            eng_idx.append(i)
    kws = obj.extractKeywordFromString(inStr)

    engStr =''
    for idx in range(len(eng_idx)):
        if idx != len(eng_idx)-1:
            if eng_idx[idx]+1 == eng_idx[idx+1]:
                engStr+=inStr[eng_idx[idx]]
            else:
                engStr+=inStr[eng_idx[idx]]
                if len(engStr)>2:
                    kws.append((engStr,10))
                engStr=''
        else:
            engStr+=inStr[eng_idx[idx]]
            if len(engStr)>2:
                kws.append((engStr,10))
            engStr=''
    return kws


def getImgDict():
    return [{'kw':'podcast','id':'17j41rqsoWVzc-HD8jvdxb651pbHJhvH8'}
    ,{'kw':'podcast','id':'1wT3uIaoe3xD-wrAo-J9eZweHEuEfI22_'}
    ,{'kw':'podcast','id':'1uaP8_xtqMn_Zbx3DX78ALdCtFjUPYgKQ'}
    ,{'kw':'podcast','id':'1L1NMByTorcDBN8EpbwwUakTexdRAiF4w'}
    ,{'kw':'youtuber','id':'17vUM8xrMgI9y1aEbAoprOxKiK9OOkipE'}
    ,{'kw':'支持者','id':'1sb-DmU5X9YE7HZLva_UueEvzcXqrKoGk'}
    ,{'kw':'app','id':'1jxoZuFlUHyl1L7-WB2ejPKBEW38bsbR6'}]

def savekeywordImage(kw,imgDict):
    highest_val = 0
    highest_d = None
    for d in imgDict:
        sim = SequenceMatcher(None, d['kw'], kw).ratio()
        #print(sim,d['kw'],kw)
        if sim>highest_val :
            highest_val = sim
            highest_d = d
    return highest_d

def get_script(cPath):
    fpath = cPath+'script.txt'

    with open(fpath, 'r',encoding="utf-8") as f:
        raw_lines = [line.strip() for line in f]
    lines =[]
    for idx in range(int(len(raw_lines)/4+1)):
        line_content = raw_lines[idx*4+2]
        lines.append(line_content)
    return lines

def rewriteScript(cPath,newlines):
    fpath = cPath+'script.txt'

    with open(fpath, 'r',encoding="utf-8") as f:
        raw_lines = [line.strip() for line in f]

    for idx in range(int(len(raw_lines)/4+1)):
        raw_lines[idx*4+2] = newlines[idx]
    
    
    f = open(fpath, 'w',encoding="utf-8")
    for l in raw_lines:
        f.write(l+'\n')
    f.close()

def parse_script(file_path):
    imgDict = getImgDict()
    with open(file_path, 'r',encoding="utf-8") as f:
        raw_lines = [line.strip() for line in f]

    dict_list = []
    sScript_dicts = []
    scriptIdx = 0
    for idx in range(int(len(raw_lines)/4+1)):
        script={}
        line_content = raw_lines[idx*4+2]
        script['content'] = line_content

        time_raw = raw_lines[idx * 4 +1 ].split(' --> ')
        start = time_raw[0].split(':')
        stop = time_raw[1].split(':')
        script['start'] = float(start[0])*3600 + float(start[1])*60 + float(start[2].replace(',','.'))
        script['stop'] = float(stop[0])*3600 + float(stop[1])*60 + float(stop[2].replace(',','.'))
        script['duration'] = script['stop']-script['start']
        duration = script['duration']
        start = script['start']
        try:
            kw= getKeyword(script['content'])
            kw.sort(key=lambda tup: tup[1], reverse=True)
            if kw[0][1]>2:
                script['kw'] = kw[0][0]
            else:
                script['kw'] = ''
        except Exception as e:
            script['kw']=''

        kwd = savekeywordImage(script['kw'],imgDict)

        
        if kwd is not None:
            script['imgid'] = kwd['id']
            imgDict.remove(kwd)
        else:
            script['imgid'] = None
   
        dict_list.append(script)
  
        accumulated_duration = 0
        for sen in shorten(script['content'],15):
            #print(sen)
            
            sScript = {}
            sScript['content'] = sen['content']
            sScript['index'] = scriptIdx
            scriptIdx+=1
            sScript['start'] = accumulated_duration+script['start']
            sScript['duration'] = duration*sen['time_ratio']
            accumulated_duration+=duration*sen['time_ratio']
            sScript_dicts.append(sScript)
    img_dicts=[]
    found = False
    start = 0
    stop = 0
    imgid=''
    imgidx = 0
    for d in dict_list:
        if d['imgid'] is not None:
            
            if found :
                img_dicts.append({'index':imgidx,'imgid':imgid,'start':start,'duration':d['start']-start})
                imgidx+=1
                start = d['start']
                imgid = d['imgid']
            else:
                found=True
                start = d['start']
                imgid = d['imgid']

        if d['start']==dict_list[-1]['start']:
            if d['imgid'] is not None:
                img_dicts.append({'index':imgidx,'imgid':d['imgid'],'start':d['start'],'duration':d['duration']})
            else:
                img_dicts.append({'index':imgidx,'imgid':imgid,'start':start,'duration':d['stop']-start})
                imgidx+=1
            
    return sScript_dicts, img_dicts

def shorten(in_str, maxLen):
    re.findall(r'[\u4e00-\u9fff]+', in_str)

    zh_idx = []
    eng_idx= []
    for i in range(len(in_str)):
        if in_str[i] > u'\u4e00' and in_str[i] < u'\u9fff':
            zh_idx.append(i)
        else:
            eng_idx.append(i)

    space_index = [m.start() for m in re.finditer(' ', in_str)]
    for idx in space_index:
        eng_idx.remove(idx)
    
    eng_range_list = []
    for k, g in groupby(enumerate(eng_idx), lambda ix : ix[0] - ix[1]):
        eng_range = list(map(itemgetter(1), g))
        eng_range_list.append(eng_range)

    total_syllable = 0
    for i in range(len(eng_range_list)):
        total_syllable += (syllable_count(in_str[eng_range_list[i][0]:eng_range_list[i][-1]+1])+0.5)
    for i in range(len(zh_idx)):
        total_syllable+=1
    
    #final chchchchchc[en][en][en]
    #[en] is a vocabulary dict with  occurence of image
    zh_eng_idx_list = []
    i = 0
    while i < len(in_str):
        if in_str[i]==' ':
            i+=1
        if i in zh_idx:
            zh_eng_idx_list.append(i)
            i+=1
        if i in eng_idx:
            for ls in eng_range_list:
                if i in ls:
                    zh_eng_idx_list.append(ls)
                    i = ls[-1]+1
                    break
            
    zh_eng_dict_list = [{'content':'','time_ratio':0}]
    idx = 0 
    current_len = 0
    sen_idx = 0
    while idx < len(zh_eng_idx_list):
        str_from_idx = ''
        sylla_cnt = 1
        if type(zh_eng_idx_list[idx])==type([]):
            str_from_idx = in_str[zh_eng_idx_list[idx][0]:zh_eng_idx_list[idx][-1]+1]+' '
            sylla_cnt = syllable_count(str_from_idx)
        else:
            str_from_idx = in_str[zh_eng_idx_list[idx]]
    
      
        if len(zh_eng_dict_list[sen_idx]['content'])+sylla_cnt>=maxLen:
            zh_eng_dict_list[sen_idx]['time_ratio'] = current_len/total_syllable
           
            zh_eng_dict_list.append({'content':'','time_ratio':0})
            sen_idx+=1
            current_len = 0
        else:
            current_len += sylla_cnt
            zh_eng_dict_list[sen_idx]['content'] += str_from_idx
            idx+=1
        
    total_ratio = 0
    for obj in zh_eng_dict_list:
        total_ratio+=obj['time_ratio']
    zh_eng_dict_list[-1]['time_ratio'] = 1-total_ratio
    return zh_eng_dict_list
def video_writer_init(path):
    w = openshot.FFmpegWriter(path)
    w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
    w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
        openshot.Fraction(1, 1), False, False, 3000000)
    return w
def cKey(r,g,b,fuzz):
    col=openshot.Color()
    col.red=openshot.Keyframe(r)
    col.green=openshot.Keyframe(g)
    col.blue=openshot.Keyframe(b)
    return openshot.ChromaKey(col, openshot.Keyframe(fuzz))

def video_photo_clip(vid=None,layer=None, position=None, end=None
    ,scale_x=1,scale_y=1,location_x=0,location_y=0,ck=None,audio=True):
    clip = openshot.Clip(vid)
    clip.Layer(layer)
    clip.Position(position)
    clip.End(end)
    clip.scale_x=openshot.Keyframe(scale_x)
    clip.scale_y=openshot.Keyframe(scale_y)
    clip.location_x=openshot.Keyframe(location_x)
    clip.location_y=openshot.Keyframe(location_y)
    
    if ck!=None:
        clip.AddEffect(ck)
    if audio==True:
        clip.has_audio=openshot.Keyframe(1)
    else:
        clip.has_audio=openshot.Keyframe(0)
    return clip

def downloadFromDrive(cPath,fid,idx):
    download_file_from_google_drive(fid, cPath+str(idx)+'img.jpg')

def download_file_from_google_drive(id, destination):
    URL = "https://docs.google.com/uc?export=download"

    session = requests.Session()

    response = session.get(URL, params = { 'id' : id }, stream = True)
    token = get_confirm_token(response)

    if token:
        params = { 'id' : id, 'confirm' : token }
        response = session.get(URL, params = params, stream = True)

    save_response_content(response, destination)    

def get_confirm_token(response):
    for key, value in response.cookies.items():
        if key.startswith('download_warning'):
            return value

    return None

def save_response_content(response, destination):
    CHUNK_SIZE = 32768

    with open(destination, "wb") as f:
        for chunk in response.iter_content(CHUNK_SIZE):
            if chunk: # filter out keep-alive new chunks
                f.write(chunk)

def call_anchor(fileName,avatar):
    conn = rpyc.classic.connect("192.168.1.111",18812)
    ros = conn.modules.os 
    rsys = conn.modules.sys 
    fr=open(fileName,'rb')# local svoice
    #warning!!!    file my be replaced by other process
    fw=conn.builtins.open('/tmp/output.mp3','wb')# remote

    while True:
        b=fr.read(1024)
        if b:
            fw.write(b)
        else:
            break

    fr.close()
    fw.close()

    val=random.randint(1000000,9999999)
    ros.chdir('/home/jared/to_video')
    ros.system('./p'+str(avatar)+'.sh '+str(val)+' &')

    while True:
        print('waiting...')
        if ros.path.exists('/tmp/results/'+str(val)):
            break
        time.sleep(5)
        print('waiting...')

    fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
    newfileName = fileName.replace('speech.mp3','speaker.mp4')
    fw=open(newfileName,'wb')#local anchor
    while True:
        b=fr.read(1024)
        if b:
            fw.write(b)
        else:
            break

    fr.close()
    fw.close()