import openshot import re from PIL import Image,ImageDraw,ImageFont import pandas as pd import os import cv2 import numpy as np # import moviepy.editor as mp import time import pysrt import shutil import rpyc import random import string import requests from bs4 import BeautifulSoup import zipfile import csv from datetime import datetime import gspread from oauth2client.service_account import ServiceAccountCredentials import fire def auth_gss_client(path, scopes): credentials = ServiceAccountCredentials.from_json_keyfile_name(path, scopes) return gspread.authorize(credentials) auth_json_path = 'noted-tesla-348011-74f70c9caeda.json' #由剛剛建立出的憑證,放置相同目錄以供引入 gss_scopes = ['https://spreadsheets.google.com/feeds'] #我們想要取用的範圍 gss_client = auth_gss_client(auth_json_path, gss_scopes) #呼叫我們的函式 #從剛剛建立的sheet,把網址中 https://docs.google.com/spreadsheets/d/〔key〕/edit 的 〔key〕的值代入 spreadsheet_key_path = '1LU5O8-oAotIFGPI9STPbElO0NHGA6eynuv9sYz81aOw' wks = gss_client.open_by_key(spreadsheet_key_path).sheet1 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_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 video_photo_clip(video=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(video) 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 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 randomString(stringLength=10): letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(stringLength)) #文字轉圖片 def txt2image(content, save_target,lang='zh',size=26,fon="input_self/font/DFT_B7.ttc"): unicode_text = trim_punctuation(content) font = '' if lang=='zh': font = ImageFont.truetype(font=fon, size=size) else : font = ImageFont.truetype(font="input_self/font/arial.ttf", size=size) W, H = (1280,500) canvas = Image.new('RGB', (W, H), "#00FF00") draw = ImageDraw.Draw(canvas) text= content if "\n" in text: w, h = draw.textsize(text.split("\n")[0],font = font) #draw.text(((W-w)/2,0), text[0:18],'black', font) text_border(draw,(W-w)/2,0,text.split("\n")[0],font,'black','white') w, h = draw.textsize(text.split("\n")[1],font = font) #draw.text(((W-w)/2,h+2), text[18:],'black', font) text_border(draw,(W-w)/2,h+2,text.split("\n")[1],font,'black','white') else: w, h = draw.textsize(content,font = font) #draw.text(((W-w)/2,0), text,'black', font) text_border(draw,(W-w)/2,0,text,font,'black','white') canvas.save(save_target, "PNG") def text_border(draw,x,y,text,font,shadowcolor,fillcolor): draw.text((x-1, y), text, font=font, fill=shadowcolor) draw.text((x+1, y), text, font=font, fill=shadowcolor) draw.text((x, y-1), text, font=font, fill=shadowcolor) draw.text((x, y+1), text, font=font, fill=shadowcolor) draw.text((x-1, y+1), text, font=font, fill=shadowcolor) draw.text((x+1, y-1), text, font=font, fill=shadowcolor) draw.text((x-1, y-1), text, font=font, fill=shadowcolor) draw.text((x+1, y+1), text, font=font, fill=shadowcolor) # thicker border draw.text((x-2, y-2), text, font=font, fill=shadowcolor) draw.text((x+2, y-2), text, font=font, fill=shadowcolor) draw.text((x-2, y+2), text, font=font, fill=shadowcolor) draw.text((x+2, y+2), text, font=font, fill=shadowcolor) # now draw the text over it draw.text((x, y), text, font=font, fill=fillcolor) def srt_to_csv(srt_file): subs = pysrt.open(srt_file) csv_file = srt_file.split('.')[0] + ".csv" with open(csv_file, 'w', newline='',encoding="big5") as csvfile: # 建立 CSV 檔寫入器 writer = csv.writer(csvfile) j=0 for context in subs: writer.writerow([context.index, context.start,context.end, context.text]) j+=1 return csv_file def csv_to_text(csv_file,text_font): text_form = [] with open(csv_file, newline='',encoding="big5") as csvfile: # 讀取 CSV 檔案內容 rows = csv.reader(csvfile) j=0 # 以迴圈輸出每一列 for row in rows: if j==0: j = 1 continue start = datetime.strptime(row[1], "%H:%M:%S,%f") end = datetime.strptime(row[2], "%H:%M:%S,%f") - datetime.strptime(row[1], "%H:%M:%S,%f") end_timeStamp=end.seconds+0.000001*end.microseconds start_timeStamp=start.minute*60+start.second+ 0.000001*start.microsecond text_form.append({'text':row[3],'start':start_timeStamp,'end':end_timeStamp,'size':36,'font':text_font}) return text_form def text_to_short_vedio( mp4_file = "output/no_captions/test.mp4", sound_file ='output/no_captions/test.mp4', output_filename="output/finally_output/demo.mp4", text_font ="input_self/font/DFT_R7.ttc"): t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO) t.Open() # 去背參數 ck = cKey(0, 254, 0, 270) ck_anchor = cKey(0, 255, 0, 320) anchor = openshot.FFmpegReader(mp4_file) anchor.Open() anchor_clip = video_photo_clip(video=anchor,layer=2,scale_x=1,scale_y=1, location_x=0,location_y=0,position=0, end=anchor.info.duration,audio=True) t.AddClip(anchor_clip) anchor.Close() number = 0 # sound_srt_file = "" # #音檔自動產生srt(逐字稿) # if ".srt" in sound_file: # sound_srt_file = sound_file # elif not sound_file is None: # cmd = "autosub -S zh-TW -D zh-TW " + sound_file # os.system(cmd) # sound_srt_file = sound_file.split('.')[0] + ".srt" # csv_file = srt_to_csv(sound_srt_file) csv_file = "output/csv_produce/test.csv" text_form = csv_to_text(csv_file,text_font) # text_form = sheet_to_text(text_font) # print(text_form) # print(sound_srt_file) #開啟srt檔 try: number = 0 for text_tmp in text_form: file_name = "input_self/tmp/save_target_" + str(number) + ".png" txt2image(text_tmp['text'], file_name,lang='zh',size = text_tmp['size'],fon = text_tmp['font']) exec('text_anchor_{} = openshot.QtImageReader("input_self/tmp/save_target_{}.png")'.format(number,number)) exec('text_anchor_{}.Open()'.format(number)) exec('text_anchor_{}.Open()'.format(number)) exec('text_anchor_clip_{} = video_photo_clip(video=text_anchor_{},layer=4,scale_x=1,scale_y=1,\ location_x=0,location_y=0.78,position=text_tmp["start"], end=text_tmp["end"],ck=ck_anchor,audio=True)'.format(number,number)) exec('t.AddClip(text_anchor_clip_{})'.format(number)) exec('text_anchor_{}.Close()'.format(number)) number = number+1 except: print("無法開啟srt檔案(字幕產生失敗)") w = video_writer_init(output_filename) w.Open() frames = int(t.info.fps)*int(anchor.info.duration) for n in range(frames): f=t.GetFrame(n) w.WriteFrame(f) t.Close() w.Close() # 刪除暫存檔案 shutil.rmtree('input_self/tmp') os.mkdir('input_self/tmp') # shutil.rmtree('input_self/tmp1') # os.mkdir('input_self/tmp1') def csv_to_text2(csv_file,text_font): text_form = [] csv_use=pd.read_csv("input/主播檔.csv") b="" for i in range(len(csv_use)): # for i in range(3): b+=str(csv_use.loc[i,['字幕']].values[0]) print(b) print(len(b)) out = re.sub(r'[^\w\s]','',b) print(out) print(len(out)) with open(csv_file, newline='',encoding="big5") as csvfile: # 讀取 CSV 檔案內容 rows = csv.reader(csvfile) j=0 # 以迴圈輸出每一列 a = "" for row in rows: if j==0: j = 1 continue start = datetime.strptime(row[1], "%H:%M:%S,%f") end = datetime.strptime(row[2], "%H:%M:%S,%f") - datetime.strptime(row[1], "%H:%M:%S,%f") end_timeStamp=end.seconds+0.000001*end.microseconds start_timeStamp=start.minute*60+start.second+ 0.000001*start.microsecond text_form.append({'text':row[3],'start':start_timeStamp,'end':end_timeStamp,'size':36,'font':text_font}) a+=row[3] print(a) print(len(a)) return text_form def sheet_to_text(text_font): ck_anchor = cKey(0, 255, 0, 320) text_form = [] for context in wks.get_all_values(): #print(context.start.minutes*60+context.start.seconds+ 0.001*context.start.milliseconds) start = datetime.strptime(context[0], "%H:%M:%S,%f") end = datetime.strptime(context[1], "%H:%M:%S,%f") - datetime.strptime(context[0], "%H:%M:%S,%f") end_timeStamp=end.seconds+0.000001*end.microseconds start_timeStamp=start.minute*60+start.second+ 0.000001*start.microsecond text_form.append({'text':context[2],'start':start_timeStamp,'end':end_timeStamp,'size':36,'font':text_font}) return text_form if __name__ == '__main__': fire.Fire(text_to_short_vedio) # fire.Fire(text_to_short_vedio( # mp4_file = "output/no_captions/test.mp4", # sound_file ='output/no_captions/test.mp4', # output_filename="output/finally_output/demo.mp4", # text_font ="input_self/font/DFT_R7.ttc")) # text_to_short_vedio( # mp4_file = "output/no_captions/test.mp4", # sound_file ='output/no_captions/test.mp4', # output_filename="output/finally_output/demo.mp4", # text_font ="input_self/font/DFT_R7.ttc") # csv_to_text2("output/csv_produce/test.csv","input_self/font/DFT_R7.ttc")