openshot_video_generator.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. from os import listdir
  2. from os.path import isfile, isdir, join
  3. import openshot
  4. import threading
  5. import zhtts
  6. import os
  7. import urllib
  8. from typing import List
  9. import requests
  10. from pydantic import BaseModel
  11. from bs4 import BeautifulSoup
  12. from PIL import Image,ImageDraw,ImageFont
  13. import pyttsx3
  14. import rpyc
  15. import random
  16. import re
  17. import time
  18. import math
  19. import dataset
  20. from datetime import datetime
  21. from gtts import gTTS
  22. dir_sound = 'mp3_track/'
  23. dir_photo = 'photo/'
  24. dir_text = 'text_file/'
  25. dir_video = 'video_material/'
  26. dir_title = 'title/'
  27. dir_subtitle = 'subtitle/'
  28. dir_anchor = 'anchor_raw/'
  29. tmp_video_dir = 'tmp_video/'
  30. video_sub_folder = 'ai_anchor_video/'
  31. dir_list = [dir_sound,dir_photo,dir_text,dir_video,dir_title,dir_subtitle,dir_anchor,tmp_video_dir]
  32. def notify_group(msg):
  33. glist=['7vilzohcyQMPLfAMRloUawiTV4vtusZhxv8Czo7AJX8','WekCRfnAirSiSxALiD6gcm0B56EejsoK89zFbIaiZQD','1dbtJHbWVbrooXmQqc4r8OyRWDryjD4TMJ6DiDsdgsX','HOB1kVNgIb81tTB4Ort1BfhVp9GFo6NlToMQg88vEhh']
  34. for gid in glist:
  35. headers = {
  36. "Authorization": "Bearer " + gid,
  37. "Content-Type": "application/x-www-form-urlencoded"
  38. }
  39. params = {"message": msg}
  40. r = requests.post("https://notify-api.line.me/api/notify",headers=headers, params=params)
  41. def cKey(r,g,b,fuzz):
  42. col=openshot.Color()
  43. col.red=openshot.Keyframe(r)
  44. col.green=openshot.Keyframe(g)
  45. col.blue=openshot.Keyframe(b)
  46. return openshot.ChromaKey(col, openshot.Keyframe(fuzz))
  47. def video_photo_clip(vid=None,layer=None, position=None, end=None
  48. ,scale_x=1,scale_y=1,location_x=0,location_y=0,ck=None,audio=True):
  49. clip = openshot.Clip(vid)
  50. clip.Layer(layer)
  51. clip.Position(position)
  52. clip.End(end)
  53. clip.scale_x=openshot.Keyframe(scale_x)
  54. clip.scale_y=openshot.Keyframe(scale_y)
  55. clip.location_x=openshot.Keyframe(location_x)
  56. clip.location_y=openshot.Keyframe(location_y)
  57. if ck!=None:
  58. clip.AddEffect(ck)
  59. if audio==True:
  60. clip.has_audio=openshot.Keyframe(1)
  61. else:
  62. clip.has_audio=openshot.Keyframe(0)
  63. return clip
  64. def myunichchar(unicode_char):
  65. mb_string = unicode_char.encode('big5')
  66. try:
  67. unicode_char = unichr(ord(mb_string[0]) << 8 | ord(mb_string[1]))
  68. except NameError:
  69. unicode_char = chr(mb_string[0] << 8 | mb_string[1])
  70. return unicode_char
  71. def get_url_type(url):
  72. req = urllib.request.Request(url, method='HEAD', headers={'User-Agent': 'Mozilla/5.0'})
  73. r = urllib.request.urlopen(req)
  74. contentType = r.getheader('Content-Type')
  75. return contentType
  76. def make_dir(name_hash):
  77. for direct in dir_list:
  78. if not os.path.isdir(direct):
  79. os.mkdir(direct)
  80. try:
  81. os.mkdir(dir_photo+name_hash)
  82. except FileExistsError:
  83. print("~~~~~~Warning~~~~~~~~~Directory " , dir_photo+name_hash , " already exists")
  84. try:
  85. os.mkdir(dir_text+name_hash)
  86. except FileExistsError:
  87. print("~~~~~~Warning~~~~~~~~~Directory " , dir_text+name_hash , " already exists")
  88. try:
  89. os.mkdir(dir_sound+name_hash)
  90. except FileExistsError:
  91. print("~~~~~~Warning~~~~~~~~~Directory " , dir_sound+name_hash , " already exists")
  92. try:
  93. os.mkdir(dir_anchor+name_hash)
  94. except FileExistsError:
  95. print("~~~~~~Warning~~~~~~~~~Directory " , dir_anchor+name_hash , " already exists")
  96. try:
  97. os.mkdir(dir_subtitle+name_hash)
  98. except FileExistsError:
  99. print("~~~~~~Warning~~~~~~~~~Directory " , dir_subtitle+name_hash , " already exists")
  100. def file_prepare(name, name_hash,text_content,image_urls,multiLang,lang='zh'):
  101. make_dir(name_hash)
  102. img_num = 1
  103. for imgu in image_urls:
  104. if get_url_type(imgu) =='video/mp4':
  105. r=requests.get(imgu)
  106. f=open(dir_photo+name_hash+"/"+str(img_num)+".mp4",'wb')
  107. for chunk in r.iter_content(chunk_size=255):
  108. if chunk:
  109. f.write(chunk)
  110. f.close()
  111. else:
  112. im = Image.open(requests.get(imgu, stream=True).raw)
  113. im= im.convert("RGB")
  114. im.save(dir_photo+name_hash+"/"+str(img_num)+".jpg")
  115. img_num+=1
  116. #save text
  117. txt_idx=0
  118. for txt in text_content:
  119. text_file = open(dir_text+name_hash+"/"+str(txt_idx)+".txt", "w")
  120. text_file.write(txt)
  121. text_file.close()
  122. txt_idx+=1
  123. print("text file made")
  124. #make mp3
  125. language = 'zh-tw'
  126. txt_idx = 0
  127. print(multiLang)
  128. for txt in text_content:
  129. if lang!='zh' or multiLang==1:
  130. print('use gtts')
  131. tts = gTTS(txt)
  132. tts.save(dir_sound+name_hash+"/"+str(txt_idx)+".mp3")
  133. else:
  134. print('use zhtts')
  135. tts = zhtts.TTS()
  136. tts.text2wav(txt,dir_sound+name_hash+"/"+str(txt_idx)+".mp3")
  137. txt_idx+=1
  138. print("mp3 file made")
  139. #make title as image
  140. txt2image_title(name, dir_title+name_hash+".png",lang)
  141. def txt2image(content, save_target,lang='zh'):
  142. unicode_text = trim_punctuation(content)
  143. font = ''
  144. if lang=='zh':
  145. font = ImageFont.truetype(font="font/DFT_B7.ttc", size=38)
  146. else :
  147. font = ImageFont.truetype(font="font/arial.ttf", size=38)
  148. text_width, text_height = font.getsize(unicode_text)
  149. canvas = Image.new('RGBA', (700, 500), (255, 0, 0, 0) )
  150. draw = ImageDraw.Draw(canvas)
  151. text= unicode_text
  152. draw.text((5,5), text, (255, 255, 0), font)
  153. canvas.save(save_target, "PNG")
  154. def txt2image_title(content, save_target, lang='zh'):
  155. unicode_text = trim_punctuation(content)
  156. font = ''
  157. if lang=='zh':
  158. font = ImageFont.truetype(font="font/DFT_B7.ttc", size=22)
  159. else :
  160. font = ImageFont.truetype(font="font/arial.ttf", size=22)
  161. text_width, text_height = font.getsize(unicode_text)
  162. canvas = Image.new('RGBA', (510, 500), (255, 0, 0, 0) )
  163. draw = ImageDraw.Draw(canvas)
  164. text= unicode_text
  165. draw.text((5,5), text, (17, 41, 167), font)
  166. canvas.save(save_target, "PNG")
  167. def call_anchor(fileName,avatar):
  168. conn = rpyc.classic.connect("192.168.1.105",18812)
  169. ros = conn.modules.os
  170. rsys = conn.modules.sys
  171. fr=open(dir_sound+fileName+".mp3",'rb')# voice
  172. #warning!!! file my be replaced by other process
  173. fw=conn.builtins.open('/tmp/output.mp3','wb')
  174. while True:
  175. b=fr.read(1024)
  176. if b:
  177. fw.write(b)
  178. else:
  179. break
  180. fr.close()
  181. fw.close()
  182. val=random.randint(1000000,9999999)
  183. ros.chdir('/home/jared/to_video')
  184. ros.system('./p'+str(avatar)+'.sh '+str(val)+' &')
  185. while True:
  186. print('waiting...')
  187. if ros.path.exists('/tmp/results/'+str(val)):
  188. break
  189. time.sleep(5)
  190. print('waiting...')
  191. fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
  192. fw=open(dir_anchor+fileName+".mp4",'wb')
  193. while True:
  194. b=fr.read(1024)
  195. if b:
  196. fw.write(b)
  197. else:
  198. break
  199. fr.close()
  200. fw.close()
  201. def trim_punctuation(s):
  202. pat_block = u'[^\u4e00-\u9fff0-9a-zA-Z]+';
  203. pattern = u'([0-9]+{0}[0-9]+)|{0}'.format(pat_block)
  204. res = re.sub(pattern, lambda x: x.group(1) if x.group(1) else u" " ,s)
  205. return res
  206. def splitter(s):
  207. for sent in re.findall(u'[^!?,。\!\?]+[!?。\!\?]?', s, flags=re.U):
  208. yield sent
  209. def split_by_pun(s):
  210. res = list(splitter(s))
  211. return res
  212. def generate_subtitle_image(name_hash,text_content):
  213. img_list = [None]*len(text_content)
  214. for idx in range(len(text_content)):
  215. img_list[idx]=[]
  216. senList = split_by_pun(text_content[idx])
  217. for inner_idx in range(len(senList)):
  218. sv_path = dir_subtitle + name_hash +'/'+str(idx)+ str(inner_idx) +'.png'
  219. sub = senList[inner_idx]
  220. txt2image(sub,sv_path)
  221. img_list[idx]+=[{"count":len(sub),"path":sv_path}]
  222. return img_list
  223. def generate_subtitle_image_ENG(name_hash,text_content):
  224. img_list = [None]*len(text_content)
  225. for idx in range(len(text_content)):
  226. sv_path = dir_subtitle + name_hash +'/'+str(idx)+'.png'
  227. sub = text_content[idx]
  228. txt2image(sub, sv_path,lang='eng')
  229. img_list[idx] = sv_path
  230. return img_list
  231. def anchor_video_v2(name_hash,name,text_content, image_urls,multiLang,avatar):
  232. print(os.getcwd())
  233. print('sub image made')
  234. file_prepare(name, name_hash, text_content,image_urls,multiLang)
  235. sub_list=generate_subtitle_image(name_hash,text_content)
  236. for fname in range(len(text_content)):
  237. call_anchor(name_hash+"/"+str(fname),avatar)
  238. print('step finish')
  239. print('called............................................')
  240. ck=cKey(0,254,0,270)
  241. ck_anchor=cKey(0,255,1,320)
  242. duration = 0
  243. #average layer level is 3
  244. t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO)
  245. t.Open()
  246. main_timer = 0
  247. LOGO_OP = openshot.FFmpegReader(dir_video+"LOGO_OP_4.mp4")
  248. LOGO_OP.Open() # Open the reader
  249. LOGO_OP_clip = video_photo_clip(vid=LOGO_OP,layer=4,position=0,end=LOGO_OP.info.duration
  250. ,location_y=-0.03,scale_x=0.8,scale_y=0.704)
  251. t.AddClip(LOGO_OP_clip)
  252. bg_head = openshot.FFmpegReader(dir_video+"complete_head_aispokesgirl.mp4")
  253. bg_head.Open()
  254. bg_head_clip = video_photo_clip(vid=bg_head,layer=2,position=0,end=LOGO_OP.info.duration,ck=ck)
  255. t.AddClip(bg_head_clip)
  256. main_timer += LOGO_OP.info.duration
  257. head_duration = LOGO_OP.info.duration
  258. bg_head.Close()
  259. LOGO_OP.Close()
  260. clip_duration=0
  261. photo_clip_list = [None]*len(text_content)
  262. img_list = [None]*len(text_content)
  263. anchor_clip_list = [None] * len(text_content)
  264. anchor_list = [None] * len(text_content)
  265. audio_clip_list = [None] * len(text_content)
  266. audio_list = [None] * len(text_content)
  267. sub_clip_list = [None] * len(text_content)
  268. sub_img_list = [None] * len(text_content)
  269. idx = 0
  270. for p in listdir(dir_photo+name_hash):
  271. anchor_list[idx] = openshot.FFmpegReader(dir_anchor+name_hash+"/"+str(idx)+".mp4")
  272. clip_duration = anchor_list[idx].info.duration
  273. anchor_list[idx].Open()
  274. anchor_clip_list[idx] = video_photo_clip(vid=anchor_list[idx],layer=4,scale_x=0.65,scale_y=0.65,
  275. location_x=0.35,location_y=0.25,position=main_timer, end=clip_duration,ck=ck_anchor,audio=False)
  276. t.AddClip(anchor_clip_list[idx])
  277. img_list[idx] = openshot.FFmpegReader(dir_photo+name_hash+'/'+p)
  278. img_list[idx].Open()
  279. photo_clip_list[idx] = video_photo_clip(vid=img_list[idx],layer=3
  280. ,scale_x=0.81,scale_y=0.68,location_y=-0.03,position=main_timer,end=clip_duration,audio=False)
  281. t.AddClip(photo_clip_list[idx])
  282. img_list[idx].Close()
  283. audio_list[idx] = openshot.FFmpegReader(dir_sound+name_hash+"/"+str(idx)+".mp3")
  284. audio_list[idx].Open()
  285. audio_clip_list[idx] = openshot.Clip(audio_list[idx])
  286. audio_clip_list[idx].Position(main_timer)
  287. audio_clip_list[idx].End(clip_duration)
  288. t.AddClip(audio_clip_list[idx])
  289. img_list[idx].Close()
  290. anchor_list[idx].Close()
  291. audio_list[idx].Close()
  292. sub_img_list[idx] = [None] * len(sub_list[idx])
  293. sub_clip_list[idx] = [None] * len(sub_list[idx])
  294. sub_timer = 0
  295. for sub_idx in range(len(sub_list[idx])):
  296. sub_img_list[idx][sub_idx] = openshot.QtImageReader(sub_list[idx][sub_idx]['path'])
  297. sub_img_list[idx][sub_idx].Open()
  298. sub_duration = 0.205*sub_list[idx][sub_idx]['count']
  299. sub_clip_list[idx][sub_idx] = video_photo_clip(vid=sub_img_list[idx][sub_idx], layer=6,location_x=0.069, location_y=0.89,position=main_timer+sub_timer,end=sub_duration)
  300. t.AddClip(sub_clip_list[idx][sub_idx])
  301. sub_img_list[idx][sub_idx].Close()
  302. sub_timer += sub_duration
  303. print(sub_list[idx][sub_idx]['path'])
  304. main_timer += clip_duration
  305. idx+=1
  306. LOGO_ED = openshot.FFmpegReader(dir_video+"LOGO_ED.avi")
  307. LOGO_ED.Open()
  308. LOGO_ED_clip = video_photo_clip(vid=LOGO_ED,layer=4,position=main_timer,end=LOGO_ED.info.duration+2
  309. ,location_x=0.005,location_y=-0.031
  310. ,scale_x=0.8,scale_y=0.6825)
  311. t.AddClip(LOGO_ED_clip)
  312. ED_duration = LOGO_ED.info.duration
  313. LOGO_ED.Close()
  314. bg = openshot.FFmpegReader(dir_video+"complete_double_aispokesgirl.mp4")
  315. bg.Open()
  316. bg_times = math.floor(main_timer+ED_duration/bg.info.duration)
  317. left_time = (main_timer+ED_duration) % bg.info.duration
  318. bg_clip_list = [None] * bg_times
  319. bg_list = [None] * bg_times
  320. bg.Close()
  321. bg_timer = head_duration
  322. for idx in range(bg_times):
  323. bg_list[idx] = openshot.FFmpegReader(dir_video+"complete_double_aispokesgirl.mp4")
  324. bg_list[idx].Open()
  325. bg_clip_list[idx] = video_photo_clip(bg_list[idx],layer=2,position=bg_timer
  326. ,end=bg_list[idx].info.duration,ck=ck)
  327. t.AddClip(bg_clip_list[idx])
  328. bg_timer += bg_list[idx].info.duration
  329. bg_list[idx].Close()
  330. bg_left = openshot.FFmpegReader(dir_video+"complete_double_aispokesgirl.mp4")
  331. bg_left.Open()
  332. bg_left_clip = video_photo_clip(bg_left,layer=2,position=bg_timer,end=left_time,ck=ck)
  333. t.AddClip(bg_left_clip)
  334. bg_left.Close()
  335. title = openshot.QtImageReader(dir_title+name_hash+".png")
  336. title.Open() # Open the reader
  337. title_clip = video_photo_clip(vid=title, layer=4,location_x=-0.047, location_y=0.801,position=0,end=head_duration+main_timer)
  338. t.AddClip(title_clip)
  339. ####start building
  340. w = openshot.FFmpegWriter(tmp_video_dir+name_hash+".mp4")
  341. w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
  342. w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
  343. openshot.Fraction(1, 1), False, False, 3000000)
  344. w.Open()
  345. #may change duration into t.info.duration
  346. frames = int(t.info.fps)*int(head_duration+main_timer+ED_duration)
  347. for n in range(frames):
  348. f=t.GetFrame(n)
  349. w.WriteFrame(f)
  350. notify_group(name+"的影片已經產生完成囉! www.choozmo.com:8168/"+video_sub_folder+name_hash+".mp4")
  351. t.Close()
  352. w.Close()
  353. print("video at : www.choozmo.com:8168/"+video_sub_folder+name_hash+".mp4")
  354. def anchor_video_eng(name_hash,name,text_content, image_urls,sub_titles,avatar):
  355. file_prepare(name, name_hash, text_content,image_urls,'eng')
  356. sub_list=generate_subtitle_image_ENG(name_hash,sub_titles)
  357. for fname in range(len(text_content)):
  358. call_anchor(name_hash+"/"+str(fname),avatar)
  359. print('step finish')
  360. print('called............................................')
  361. ck=cKey(0,254,0,270)
  362. ck_anchor=cKey(0,255,1,320)
  363. duration = 0
  364. #average layer level is 3
  365. t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO)
  366. t.Open()
  367. main_timer = 0
  368. #add logo
  369. LOGO_OP = openshot.FFmpegReader(dir_video+"LOGO_OP_4.mp4")
  370. LOGO_OP.Open() # Open the reader
  371. LOGO_OP_clip = video_photo_clip(vid=LOGO_OP,layer=4,position=0,end=LOGO_OP.info.duration
  372. ,location_y=-0.03,scale_x=0.8,scale_y=0.704)
  373. t.AddClip(LOGO_OP_clip)
  374. #add background video (head is different)
  375. bg_head = openshot.FFmpegReader(dir_video+"complete_head_aispokesgirl.mp4")
  376. bg_head.Open()
  377. bg_head_clip = video_photo_clip(vid=bg_head,layer=2,position=0,end=LOGO_OP.info.duration,ck=ck)
  378. t.AddClip(bg_head_clip)
  379. main_timer += LOGO_OP.info.duration
  380. head_duration = LOGO_OP.info.duration
  381. bg_head.Close()
  382. LOGO_OP.Close()
  383. #prepare empty list
  384. clip_duration=0
  385. photo_clip_list = [None]*len(text_content)
  386. img_list = [None]*len(text_content)
  387. anchor_clip_list = [None] * len(text_content)
  388. anchor_list = [None] * len(text_content)
  389. audio_clip_list = [None] * len(text_content)
  390. audio_list = [None] * len(text_content)
  391. sub_clip_list = [None] * len(text_content)
  392. #openshot image holder
  393. sub_img_list = [None] * len(text_content)
  394. idx = 0
  395. for p in listdir(dir_photo+name_hash):
  396. anchor_list[idx] = openshot.FFmpegReader(dir_anchor+name_hash+"/"+str(idx)+".mp4")
  397. clip_duration = anchor_list[idx].info.duration
  398. anchor_list[idx].Open()
  399. anchor_clip_list[idx] = video_photo_clip(vid=anchor_list[idx],layer=4,scale_x=0.65,scale_y=0.65,
  400. location_x=0.35,location_y=0.25,position=main_timer, end=clip_duration,ck=ck_anchor,audio=False)
  401. t.AddClip(anchor_clip_list[idx])
  402. #insert image
  403. img_list[idx] = openshot.FFmpegReader(dir_photo+name_hash+'/'+p)
  404. img_list[idx].Open()
  405. photo_clip_list[idx] = video_photo_clip(vid=img_list[idx],layer=3
  406. ,scale_x=0.81,scale_y=0.68,location_y=-0.03,position=main_timer,end=clip_duration,audio=False)
  407. t.AddClip(photo_clip_list[idx])
  408. img_list[idx].Close()
  409. #insert audio (speech)
  410. audio_list[idx] = openshot.FFmpegReader(dir_sound+name_hash+"/"+str(idx)+".mp3")
  411. audio_list[idx].Open()
  412. audio_clip_list[idx] = openshot.Clip(audio_list[idx])
  413. audio_clip_list[idx].Position(main_timer)
  414. audio_clip_list[idx].End(clip_duration)
  415. t.AddClip(audio_clip_list[idx])
  416. #insert subtitle
  417. sub_img_list[idx] = openshot.QtImageReader(sub_list[idx])
  418. sub_img_list[idx].Open()
  419. sub_clip_list[idx] = video_photo_clip(vid=sub_img_list[idx], layer=6,location_x=0.069, location_y=0.89,position=main_timer,end=clip_duration)
  420. t.AddClip(sub_clip_list[idx])
  421. img_list[idx].Close()
  422. anchor_list[idx].Close()
  423. audio_list[idx].Close()
  424. sub_img_list[idx].Close()
  425. main_timer += clip_duration
  426. idx+=1
  427. LOGO_ED = openshot.FFmpegReader(dir_video+"ED_ENG.mp4")
  428. LOGO_ED.Open()
  429. LOGO_ED_clip = video_photo_clip(vid=LOGO_ED,layer=4,position=main_timer,end=LOGO_ED.info.duration+2
  430. ,location_x=0.005,location_y=-0.031
  431. ,scale_x=0.8,scale_y=0.6825)
  432. t.AddClip(LOGO_ED_clip)
  433. ED_duration = LOGO_ED.info.duration
  434. LOGO_ED.Close()
  435. bg = openshot.FFmpegReader(dir_video+"complete_double_aispokesgirl.mp4")
  436. bg.Open()
  437. bg_times = math.floor(main_timer+ED_duration/bg.info.duration)
  438. left_time = (main_timer+ED_duration) % bg.info.duration
  439. bg_clip_list = [None] * bg_times
  440. bg_list = [None] * bg_times
  441. bg.Close()
  442. bg_timer = head_duration
  443. for idx in range(bg_times):
  444. bg_list[idx] = openshot.FFmpegReader(dir_video+"complete_double_aispokesgirl.mp4")
  445. bg_list[idx].Open()
  446. bg_clip_list[idx] = video_photo_clip(bg_list[idx],layer=2,position=bg_timer
  447. ,end=bg_list[idx].info.duration,ck=ck)
  448. t.AddClip(bg_clip_list[idx])
  449. bg_timer += bg_list[idx].info.duration
  450. bg_list[idx].Close()
  451. bg_left = openshot.FFmpegReader(dir_video+"complete_double_aispokesgirl.mp4")
  452. bg_left.Open()
  453. bg_left_clip = video_photo_clip(bg_left,layer=2,position=bg_timer,end=left_time,ck=ck)
  454. t.AddClip(bg_left_clip)
  455. bg_left.Close()
  456. title = openshot.QtImageReader(dir_title+name_hash+".png")
  457. title.Open() # Open the reader
  458. title_clip = video_photo_clip(vid=title, layer=4,location_x=-0.047, location_y=0.801,position=0,end=head_duration+main_timer)
  459. t.AddClip(title_clip)
  460. ####start building
  461. w = openshot.FFmpegWriter(tmp_video_dir+name_hash+".mp4")
  462. w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
  463. w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
  464. openshot.Fraction(1, 1), False, False, 3000000)
  465. w.Open()
  466. #may change duration into t.info.duration
  467. frames = int(t.info.fps)*int(head_duration+main_timer+ED_duration)
  468. for n in range(frames):
  469. f=t.GetFrame(n)
  470. w.WriteFrame(f)
  471. notify_group(name+"(ENG)的影片已經產生完成囉! www.choozmo.com:8168/"+video_sub_folder+name_hash+".mp4")
  472. t.Close()
  473. w.Close()
  474. print("video at : www.choozmo.com:8168/"+video_sub_folder+name_hash+".mp4")
  475. #line notifs
  476. class video_service(rpyc.Service):
  477. def exposed_call_video(self,name_hash,name,text_content, image_urls,multiLang,avatar):
  478. anchor_video_v2(name_hash,name,text_content, image_urls,multiLang,avatar)
  479. def exposed_call_video_eng(self,name_hash,name,text_content, image_urls,sub_titles,avatar):
  480. anchor_video_eng(name_hash,name,text_content, image_urls,sub_titles,avatar)
  481. from rpyc.utils.server import ThreadedServer
  482. t = ThreadedServer(video_service, port=8858)
  483. print('service started')
  484. t.start()