main.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. from fastapi import FastAPI,Cookie, Depends, FastAPI, Query, WebSocket, status
  2. import openshot
  3. from os import listdir
  4. from os.path import isfile, isdir, join
  5. import threading
  6. import zhtts
  7. import os
  8. import urllib
  9. from typing import List
  10. import requests
  11. from pydantic import BaseModel
  12. from bs4 import BeautifulSoup
  13. import time
  14. from PIL import Image,ImageDraw,ImageFont
  15. import pyttsx3
  16. import rpyc
  17. import random
  18. import time
  19. import math
  20. import hashlib
  21. import re
  22. import urllib.request
  23. from fastapi.responses import FileResponse
  24. from websocket import create_connection
  25. #service nginx restart
  26. #uvicorn main:app --host="0.0.0.0" --reload --port 8888
  27. app = FastAPI()
  28. origins = [
  29. "https://hhh.com.tw"
  30. "http://172.105.205.52",
  31. "http://172.105.205.52:8001",
  32. "http://172.104.93.163",
  33. ]
  34. app.add_middleware(
  35. CORSMiddleware,
  36. # allow_origins=origins,
  37. allow_origins=["*"],
  38. allow_credentials=True,
  39. allow_methods=["*"],
  40. allow_headers=["*"],
  41. )
  42. dir_sound = 'mp3_track/'
  43. dir_photo = 'photo/'
  44. dir_text = 'text_file/'
  45. dir_video = 'video_material/'
  46. dir_title = 'title/'
  47. dir_subtitle = 'subtitle/'
  48. dir_anchor = 'anchor_raw/'
  49. class request(BaseModel):
  50. name: str
  51. text_content: str
  52. image_urls: List[str]
  53. class QQ(BaseModel):
  54. n1: str
  55. n2: str
  56. class request2(BaseModel):
  57. name: str
  58. text_content: List[str]
  59. image_urls: List[str]
  60. class anchor_request(BaseModel):
  61. name: str
  62. text_content: str
  63. image_urls: List[str]
  64. @app.get("/")
  65. async def root():
  66. return {"message": "Hello, this is index"}
  67. @app.get("/index2")
  68. async def index2():
  69. return FileResponse('index2.html')
  70. @app.get("/script_msg.js")
  71. async def index2():
  72. return FileResponse('script_msg.js')
  73. @app.get("/style.css")
  74. async def index2():
  75. return FileResponse('style.css')
  76. @app.get("/progress_page")
  77. async def progress_page():
  78. return FileResponse('progress.html')
  79. @app.post("/make_anchor_video_v2")
  80. async def make_anchor_video_v2(req:request2):
  81. x = threading.Thread(target=anchor_video_v3, args=(req.name, req.text_content, req.image_urls))
  82. x.start()
  83. #return RedirectResponse("https://www.choozmo.com/progress_page")
  84. return {"msg":"製作影片需要時間,請您耐心等候 稍後可以在www.choozmo.com:8168/"+req.name+".mp4 中觀看"}
  85. @app.websocket("/progress")
  86. async def websocket_endpoint(websocket: WebSocket):
  87. await websocket.accept()
  88. while True:
  89. data = await websocket.receive_text()
  90. await websocket.send_text({data})
  91. def notify_group(msg):
  92. headers = {
  93. "Authorization": "Bearer " + "WekCRfnAirSiSxALiD6gcm0B56EejsoK89zFbIaiZQD",
  94. "Content-Type": "application/x-www-form-urlencoded"
  95. }
  96. params = {"message": msg}
  97. r = requests.post("https://notify-api.line.me/api/notify",headers=headers, params=params)
  98. #print(r)
  99. def cKey(r,g,b,fuzz):
  100. col=openshot.Color()
  101. col.red=openshot.Keyframe(r)
  102. col.green=openshot.Keyframe(g)
  103. col.blue=openshot.Keyframe(b)
  104. return openshot.ChromaKey(col, openshot.Keyframe(fuzz))
  105. def video_photo_clip(vid=None,layer=None, position=None, end=None
  106. ,scale_x=1,scale_y=1,location_x=0,location_y=0,ck=None,audio=True):
  107. clip = openshot.Clip(vid)
  108. clip.Layer(layer)
  109. clip.Position(position)
  110. clip.End(end)
  111. clip.scale_x=openshot.Keyframe(scale_x)
  112. clip.scale_y=openshot.Keyframe(scale_y)
  113. clip.location_x=openshot.Keyframe(location_x)
  114. clip.location_y=openshot.Keyframe(location_y)
  115. if ck!=None:
  116. clip.AddEffect(ck)
  117. if audio==True:
  118. clip.has_audio=openshot.Keyframe(1)
  119. else:
  120. clip.has_audio=openshot.Keyframe(0)
  121. return clip
  122. def myunichchar(unicode_char):
  123. mb_string = unicode_char.encode('big5')
  124. try:
  125. unicode_char = unichr(ord(mb_string[0]) << 8 | ord(mb_string[1]))
  126. except NameError:
  127. unicode_char = chr(mb_string[0] << 8 | mb_string[1])
  128. return unicode_char
  129. def file_prepare(name, name_hash,text_content,image_urls):
  130. #save image
  131. try:
  132. os.mkdir(dir_photo+name_hash)
  133. except FileExistsError:
  134. print("Directory " , dir_photo+name_hash , " already exists")
  135. img_num = 1
  136. for imgu in image_urls:
  137. im = Image.open(requests.get(imgu, stream=True).raw)
  138. im.save(dir_photo+name_hash+"/"+str(img_num)+".jpg")
  139. img_num+=1
  140. #save text
  141. text_file = open(dir_text+name_hash+".txt", "w")
  142. text_file.write(text_content)
  143. text_file.close()
  144. print("text file made")
  145. #make mp3
  146. tts = zhtts.TTS()
  147. tts.text2wav(text_content,dir_sound+name_hash+".mp3")
  148. print("mp3 file made")
  149. #make title as image
  150. txt2image(name, dir_title+name_hash+".png")
  151. def get_url_type(url):
  152. req = urllib.request.Request(url, method='HEAD', headers={'User-Agent': 'Mozilla/5.0'})
  153. r = urllib.request.urlopen(req)
  154. contentType = r.getheader('Content-Type')
  155. return contentType
  156. def downloadfile(name,url):
  157. name=name+".mp4"
  158. def make_dir(name_hash):
  159. #save image
  160. try:
  161. os.mkdir(dir_photo+name_hash)
  162. except FileExistsError:
  163. print("~~~~~~Warning~~~~~~~~~Directory " , dir_photo+name_hash , " already exists")
  164. try:
  165. os.mkdir(dir_text+name_hash)
  166. except FileExistsError:
  167. print("~~~~~~Warning~~~~~~~~~Directory " , dir_text+name_hash , " already exists")
  168. try:
  169. os.mkdir(dir_sound+name_hash)
  170. except FileExistsError:
  171. print("~~~~~~Warning~~~~~~~~~Directory " , dir_sound+name_hash , " already exists")
  172. try:
  173. os.mkdir(dir_video+name_hash)
  174. except FileExistsError:
  175. print("~~~~~~Warning~~~~~~~~~Directory " , dir_video+name_hash , " already exists")
  176. try:
  177. os.mkdir(dir_anchor+name_hash)
  178. except FileExistsError:
  179. print("~~~~~~Warning~~~~~~~~~Directory " , dir_anchor+name_hash , " already exists")
  180. try:
  181. os.mkdir(dir_subtitle+name_hash)
  182. except FileExistsError:
  183. print("~~~~~~Warning~~~~~~~~~Directory " , dir_subtitle+name_hash , " already exists")
  184. def file_prepare_v2(name, name_hash,text_content,image_urls):
  185. make_dir(name_hash)
  186. img_num = 1
  187. for imgu in image_urls:
  188. if get_url_type(imgu) =='video/mp4':
  189. r=requests.get(imgu)
  190. f=open(dir_photo+name_hash+"/"+str(img_num)+".mp4",'wb')
  191. for chunk in r.iter_content(chunk_size=255):
  192. if chunk:
  193. f.write(chunk)
  194. f.close()
  195. else:
  196. im = Image.open(requests.get(imgu, stream=True).raw)
  197. im= im.convert("RGB")
  198. im.save(dir_photo+name_hash+"/"+str(img_num)+".jpg")
  199. img_num+=1
  200. #save text
  201. txt_idx=0
  202. for txt in text_content:
  203. text_file = open(dir_text+name_hash+"/"+str(txt_idx)+".txt", "w")
  204. text_file.write(txt)
  205. text_file.close()
  206. txt_idx+=1
  207. print("text file made")
  208. #make mp3
  209. language = 'zh-tw'
  210. txt_idx = 0
  211. for txt in text_content:
  212. tts = zhtts.TTS()
  213. tts.text2wav(txt,dir_sound+name_hash+"/"+str(txt_idx)+".mp3")
  214. txt_idx+=1
  215. print("mp3 file made")
  216. #make title as image
  217. txt2image_title(name, dir_title+name_hash+".png")
  218. def txt2image(content, save_target):
  219. unicode_text = trim_punctuation(content)
  220. font = ImageFont.truetype(font="DFT_B7.ttc", size=38)
  221. text_width, text_height = font.getsize(unicode_text)
  222. canvas = Image.new('RGBA', (700, 500), (255, 0, 0, 0) )
  223. draw = ImageDraw.Draw(canvas)
  224. text= unicode_text
  225. draw.text((5,5), text, (255, 255, 0), font)
  226. canvas.save(save_target, "PNG")
  227. def txt2image_title(content, save_target):
  228. unicode_text = trim_punctuation(content)
  229. font = ImageFont.truetype(font="DFT_B7.ttc", size=28)
  230. text_width, text_height = font.getsize(unicode_text)
  231. canvas = Image.new('RGBA', (510, 500), (255, 0, 0, 0) )
  232. draw = ImageDraw.Draw(canvas)
  233. text= unicode_text
  234. draw.text((5,5), text, (17, 41, 167), font)
  235. canvas.save(save_target, "PNG")
  236. '''
  237. def txt2image_title(content, save_target):
  238. unicode_text =content
  239. font = ImageFont.truetype("font.ttf", 23,encoding='big5')
  240. text_width, text_height = font.getsize(unicode_text)
  241. canvas = Image.new('RGBA', (500, 500), (255, 0, 0, 0) )
  242. draw = ImageDraw.Draw(canvas)
  243. text=''
  244. for c in unicode_text:
  245. if len(re.findall(r'[\u4e00-\u9fff]+', c))>0:
  246. text+=myunichchar(c)
  247. else:
  248. text+=c
  249. draw.text((5,5), text, (17, 41, 167), font)
  250. canvas.save(save_target, "PNG")
  251. '''
  252. def call_achor_video_v2(fileName):
  253. conn = rpyc.classic.connect("192.168.1.105",18812)
  254. ros = conn.modules.os
  255. rsys = conn.modules.sys
  256. fr=open(dir_sound+fileName+".mp3",'rb')# voice
  257. #warning!!! file my be replaced by other process
  258. fw=conn.builtins.open('/tmp/output.mp3','wb')
  259. while True:
  260. b=fr.read(1024)
  261. if b:
  262. fw.write(b)
  263. else:
  264. break
  265. fr.close()
  266. fw.close()
  267. val=random.randint(1000000,9999999)
  268. ros.chdir('/home/jared/to_video')
  269. ros.system('./p6.sh '+str(val)+' &')
  270. while True:
  271. print('waiting...')
  272. if ros.path.exists('/tmp/results/'+str(val)):
  273. break
  274. time.sleep(5)
  275. print('waiting...')
  276. fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
  277. fw=open(dir_anchor+fileName+".mp4",'wb')#peggy1_1
  278. while True:
  279. b=fr.read(1024)
  280. if b:
  281. fw.write(b)
  282. else:
  283. break
  284. fr.close()
  285. fw.close()
  286. def call_achor_video(name):
  287. conn = rpyc.classic.connect("192.168.1.105",18812)
  288. ros = conn.modules.os
  289. rsys = conn.modules.sys
  290. fr=open(dir_sound+name+".mp3",'rb')# voice
  291. #warning!!! file my be replaced by other process
  292. fw=conn.builtins.open('/tmp/output.mp3','wb')
  293. while True:
  294. b=fr.read(1024)
  295. if b:
  296. fw.write(b)
  297. else:
  298. break
  299. fr.close()
  300. fw.close()
  301. val=random.randint(1000000,9999999)
  302. ros.chdir('/home/jared/to_video')
  303. ros.system('./p6.sh '+str(val)+' &')
  304. while True:
  305. print('waiting...')
  306. if ros.path.exists('/tmp/results/'+str(val)):
  307. break
  308. time.sleep(15)
  309. print('waiting...')
  310. fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
  311. fw=open(dir_anchor+name+'.mp4','wb')#peggy1_1
  312. while True:
  313. b=fr.read(1024)
  314. if b:
  315. fw.write(b)
  316. else:
  317. break
  318. fr.close()
  319. fw.close()
  320. print('called..............................................')
  321. def trim_punctuation(s):
  322. pat_block = u'[^\u4e00-\u9fff0-9a-zA-Z]+';
  323. pattern = u'([0-9]+{0}[0-9]+)|{0}'.format(pat_block)
  324. res = re.sub(pattern, lambda x: x.group(1) if x.group(1) else u"" ,s)
  325. return res
  326. def splitter(s):
  327. for sent in re.findall(u'[^!?,。\!\?]+[!?。\!\?]?', s, flags=re.U):
  328. yield sent
  329. def split_by_pun(s):
  330. res = list(splitter(s))
  331. return res
  332. def generate_subtitle_image(name_hash,text_content):
  333. img_list = [None]*len(text_content)
  334. for idx in range(len(text_content)):
  335. img_list[idx]=[]
  336. senList = split_by_pun(text_content[idx])
  337. for inner_idx in range(len(senList)):
  338. sv_path = dir_subtitle + name_hash +'/'+str(idx)+ str(inner_idx) +'.png'
  339. sub = senList[inner_idx]
  340. txt2image(sub,sv_path)
  341. img_list[idx]+=[{"count":len(sub),"path":sv_path}]
  342. return img_list
  343. def anchor_video_v2(name,text_content, image_urls):
  344. #ws = create_connection("ws://www.choozmo.com/progress")
  345. progress = 0
  346. m = hashlib.md5()
  347. m.update(name.encode("utf-8"))
  348. name_hash = m.hexdigest()
  349. print('sub image made')
  350. file_prepare_v2(name, name_hash, text_content,image_urls)
  351. progress = 10
  352. #ws.send(progress)
  353. sub_list=generate_subtitle_image(name_hash,text_content)
  354. progress = 20
  355. #ws.send(progress)
  356. progress_per_video = int(40/len(text_content))
  357. for fname in range(len(text_content)):
  358. call_achor_video_v2(name_hash+"/"+str(fname))
  359. progress += progress_per_video
  360. #ws.send(progress)
  361. print('step finish')
  362. print('called............................................')
  363. ck=cKey(0,254,0,150)
  364. ck_anchor=cKey(0,255,1,320)
  365. duration = 0
  366. #average layer level is 3
  367. t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO)
  368. t.Open()
  369. main_timer = 0
  370. LOGO_OP = openshot.FFmpegReader(dir_video+"LOGO_OP.mp4")
  371. LOGO_OP.Open() # Open the reader
  372. LOGO_OP_clip = video_photo_clip(vid=LOGO_OP,layer=4,position=0,end=LOGO_OP.info.duration
  373. ,location_y=-0.03,scale_x=0.8,scale_y=0.71)
  374. t.AddClip(LOGO_OP_clip)
  375. bg_head = openshot.FFmpegReader(dir_video+"bg_head.avi")
  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. progress += 10
  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. sub_img_list = [None] * len(text_content)
  393. idx = 0
  394. for p in listdir(dir_photo+name_hash):
  395. anchor_list[idx] = openshot.FFmpegReader(dir_anchor+name_hash+"/"+str(idx)+".mp4")
  396. clip_duration = anchor_list[idx].info.duration
  397. anchor_list[idx].Open()
  398. anchor_clip_list[idx] = video_photo_clip(vid=anchor_list[idx],layer=4,scale_x=0.65,scale_y=0.65,
  399. location_x=0.35,location_y=0.25,position=main_timer, end=clip_duration,ck=ck_anchor,audio=False)
  400. t.AddClip(anchor_clip_list[idx])
  401. img_list[idx] = openshot.FFmpegReader(dir_photo+name_hash+'/'+p)
  402. img_list[idx].Open()
  403. photo_clip_list[idx] = video_photo_clip(vid=img_list[idx],layer=3
  404. ,scale_x=0.81,scale_y=0.68,location_y=-0.03,position=main_timer,end=clip_duration,audio=False)
  405. t.AddClip(photo_clip_list[idx])
  406. img_list[idx].Close()
  407. audio_list[idx] = openshot.FFmpegReader(dir_sound+name_hash+"/"+str(idx)+".mp3")
  408. audio_list[idx].Open()
  409. audio_clip_list[idx] = openshot.Clip(audio_list[idx])
  410. audio_clip_list[idx].Position(main_timer)
  411. audio_clip_list[idx].End(clip_duration)
  412. t.AddClip(audio_clip_list[idx])
  413. img_list[idx].Close()
  414. anchor_list[idx].Close()
  415. audio_list[idx].Close()
  416. sub_img_list[idx] = [None] * len(sub_list[idx])
  417. sub_clip_list[idx] = [None] * len(sub_list[idx])
  418. sub_timer = 0
  419. for sub_idx in range(len(sub_list[idx])):
  420. sub_img_list[idx][sub_idx] = openshot.QtImageReader(sub_list[idx][sub_idx]['path'])
  421. sub_img_list[idx][sub_idx].Open()
  422. sub_duration = 0.205*sub_list[idx][sub_idx]['count']
  423. 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)
  424. t.AddClip(sub_clip_list[idx][sub_idx])
  425. sub_img_list[idx][sub_idx].Close()
  426. sub_timer += sub_duration
  427. print(sub_list[idx][sub_idx]['path'])
  428. main_timer += clip_duration
  429. idx+=1
  430. progress+=10
  431. #ws.send(progress)
  432. LOGO_ED = openshot.FFmpegReader(dir_video+"LOGO_ED.avi")
  433. LOGO_ED.Open()
  434. LOGO_ED_clip = video_photo_clip(vid=LOGO_ED,layer=4,position=main_timer,end=LOGO_ED.info.duration
  435. ,location_y=-0.03,scale_x=0.8,scale_y=0.71)
  436. t.AddClip(LOGO_ED_clip)
  437. ED_duration = LOGO_ED.info.duration
  438. LOGO_ED.Close()
  439. bg = openshot.FFmpegReader(dir_video+"bg.mp4")
  440. bg.Open()
  441. bg_times = math.floor(main_timer+ED_duration/bg.info.duration)
  442. left_time = (main_timer+ED_duration) % bg.info.duration
  443. bg_clip_list = [None] * bg_times
  444. bg_list = [None] * bg_times
  445. bg.Close()
  446. bg_timer = head_duration
  447. for idx in range(bg_times):
  448. bg_list[idx] = openshot.FFmpegReader(dir_video+"bg.mp4")
  449. bg_list[idx].Open()
  450. bg_clip_list[idx] = video_photo_clip(bg_list[idx],layer=2,position=bg_timer
  451. ,end=bg_list[idx].info.duration,ck=ck)
  452. t.AddClip(bg_clip_list[idx])
  453. bg_timer += bg_list[idx].info.duration
  454. bg_list[idx].Close()
  455. bg_left = openshot.FFmpegReader(dir_video+"bg.mp4")
  456. bg_left.Open()
  457. bg_left_clip = video_photo_clip(bg_left,layer=2,position=bg_timer,end=left_time,ck=ck)
  458. t.AddClip(bg_left_clip)
  459. bg_left.Close()
  460. title = openshot.QtImageReader(dir_title+name_hash+".png")
  461. title.Open() # Open the reader
  462. title_clip = video_photo_clip(vid=title, layer=4,location_x=-0.047, location_y=0.801,position=0,end=head_duration+main_timer)
  463. t.AddClip(title_clip)
  464. ####start building
  465. w = openshot.FFmpegWriter("../html/"+name_hash+".mp4")
  466. w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
  467. w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
  468. openshot.Fraction(1, 1), False, False, 3000000)
  469. w.Open()
  470. #may change duration into t.info.duration
  471. for n in range(int(t.info.fps)*int(head_duration+main_timer+ED_duration)):
  472. f=t.GetFrame(n)
  473. w.WriteFrame(f)
  474. t.Close()
  475. w.Close()
  476. print("Raw Video done")
  477. print("video at : www.choozmo.com:8168/"+name_hash+".mp4")
  478. progress = 100
  479. #ws.send(progress)
  480. #line notifs
  481. notify_group(name+"的影片已經產生完成囉! www.choozmo.com:8168/"+name_hash+".mp4")
  482. def anchor_video_v3(name,text_content, image_urls):
  483. ws = create_connection("ws://www.choozmo.com:8888/progress")
  484. progress = 0
  485. m = hashlib.md5()
  486. m.update(name.encode("utf-8"))
  487. name_hash = m.hexdigest()
  488. print('sub image made')
  489. file_prepare_v2(name, name_hash, text_content,image_urls)
  490. progress = 10
  491. ws.send(progress)
  492. sub_list=generate_subtitle_image(name_hash,text_content)
  493. progress = 20
  494. ws.send(progress)
  495. progress_per_video = int(40/len(text_content))
  496. for fname in range(len(text_content)):
  497. call_achor_video_v2(name_hash+"/"+str(fname))
  498. progress += progress_per_video
  499. ws.send(progress)
  500. print('step finish')
  501. print('called............................................')
  502. ck=cKey(0,254,0,150)
  503. ck_anchor=cKey(0,255,1,320)
  504. duration = 0
  505. #average layer level is 3
  506. t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO)
  507. t.Open()
  508. main_timer = 0
  509. LOGO_OP = openshot.FFmpegReader(dir_video+"LOGO_OP.mp4")
  510. LOGO_OP.Open() # Open the reader
  511. LOGO_OP_clip = video_photo_clip(vid=LOGO_OP,layer=4,position=0,end=LOGO_OP.info.duration
  512. ,location_y=-0.03,scale_x=0.8,scale_y=0.71)
  513. t.AddClip(LOGO_OP_clip)
  514. bg_head = openshot.FFmpegReader(dir_video+"bg_head.avi")
  515. bg_head.Open()
  516. bg_head_clip = video_photo_clip(vid=bg_head,layer=2,position=0,end=LOGO_OP.info.duration,ck=ck)
  517. t.AddClip(bg_head_clip)
  518. main_timer += LOGO_OP.info.duration
  519. head_duration = LOGO_OP.info.duration
  520. bg_head.Close()
  521. LOGO_OP.Close()
  522. progress += 10
  523. clip_duration=0
  524. photo_clip_list = [None]*len(text_content)
  525. img_list = [None]*len(text_content)
  526. anchor_clip_list = [None] * len(text_content)
  527. anchor_list = [None] * len(text_content)
  528. audio_clip_list = [None] * len(text_content)
  529. audio_list = [None] * len(text_content)
  530. sub_clip_list = [None] * len(text_content)
  531. sub_img_list = [None] * len(text_content)
  532. idx = 0
  533. for p in listdir(dir_photo+name_hash):
  534. anchor_list[idx] = openshot.FFmpegReader(dir_anchor+name_hash+"/"+str(idx)+".mp4")
  535. clip_duration = anchor_list[idx].info.duration
  536. anchor_list[idx].Open()
  537. anchor_clip_list[idx] = video_photo_clip(vid=anchor_list[idx],layer=4,scale_x=0.65,scale_y=0.65,
  538. location_x=0.35,location_y=0.25,position=main_timer, end=clip_duration,ck=ck_anchor,audio=False)
  539. t.AddClip(anchor_clip_list[idx])
  540. img_list[idx] = openshot.FFmpegReader(dir_photo+name_hash+'/'+p)
  541. img_list[idx].Open()
  542. photo_clip_list[idx] = video_photo_clip(vid=img_list[idx],layer=3
  543. ,scale_x=0.81,scale_y=0.68,location_y=-0.03,position=main_timer,end=clip_duration,audio=False)
  544. t.AddClip(photo_clip_list[idx])
  545. img_list[idx].Close()
  546. audio_list[idx] = openshot.FFmpegReader(dir_sound+name_hash+"/"+str(idx)+".mp3")
  547. audio_list[idx].Open()
  548. audio_clip_list[idx] = openshot.Clip(audio_list[idx])
  549. audio_clip_list[idx].Position(main_timer)
  550. audio_clip_list[idx].End(clip_duration)
  551. t.AddClip(audio_clip_list[idx])
  552. img_list[idx].Close()
  553. anchor_list[idx].Close()
  554. audio_list[idx].Close()
  555. sub_img_list[idx] = [None] * len(sub_list[idx])
  556. sub_clip_list[idx] = [None] * len(sub_list[idx])
  557. sub_timer = 0
  558. for sub_idx in range(len(sub_list[idx])):
  559. sub_img_list[idx][sub_idx] = openshot.QtImageReader(sub_list[idx][sub_idx]['path'])
  560. sub_img_list[idx][sub_idx].Open()
  561. sub_duration = 0.205*sub_list[idx][sub_idx]['count']
  562. 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)
  563. t.AddClip(sub_clip_list[idx][sub_idx])
  564. sub_img_list[idx][sub_idx].Close()
  565. sub_timer += sub_duration
  566. print(sub_list[idx][sub_idx]['path'])
  567. main_timer += clip_duration
  568. idx+=1
  569. progress+=10
  570. ws.send(progress)
  571. LOGO_ED = openshot.FFmpegReader(dir_video+"LOGO_ED.avi")
  572. LOGO_ED.Open()
  573. LOGO_ED_clip = video_photo_clip(vid=LOGO_ED,layer=4,position=main_timer,end=LOGO_ED.info.duration
  574. ,location_y=-0.03,scale_x=0.8,scale_y=0.71)
  575. t.AddClip(LOGO_ED_clip)
  576. ED_duration = LOGO_ED.info.duration
  577. LOGO_ED.Close()
  578. bg = openshot.FFmpegReader(dir_video+"bg.mp4")
  579. bg.Open()
  580. bg_times = math.floor(main_timer+ED_duration/bg.info.duration)
  581. left_time = (main_timer+ED_duration) % bg.info.duration
  582. bg_clip_list = [None] * bg_times
  583. bg_list = [None] * bg_times
  584. bg.Close()
  585. bg_timer = head_duration
  586. for idx in range(bg_times):
  587. bg_list[idx] = openshot.FFmpegReader(dir_video+"bg.mp4")
  588. bg_list[idx].Open()
  589. bg_clip_list[idx] = video_photo_clip(bg_list[idx],layer=2,position=bg_timer
  590. ,end=bg_list[idx].info.duration,ck=ck)
  591. t.AddClip(bg_clip_list[idx])
  592. bg_timer += bg_list[idx].info.duration
  593. bg_list[idx].Close()
  594. bg_left = openshot.FFmpegReader(dir_video+"bg.mp4")
  595. bg_left.Open()
  596. bg_left_clip = video_photo_clip(bg_left,layer=2,position=bg_timer,end=left_time,ck=ck)
  597. t.AddClip(bg_left_clip)
  598. bg_left.Close()
  599. title = openshot.QtImageReader(dir_title+name_hash+".png")
  600. title.Open() # Open the reader
  601. title_clip = video_photo_clip(vid=title, layer=4,location_x=-0.047, location_y=0.801,position=0,end=head_duration+main_timer)
  602. t.AddClip(title_clip)
  603. ####start building
  604. w = openshot.FFmpegWriter("../html/"+name_hash+".mp4")
  605. w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
  606. w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
  607. openshot.Fraction(1, 1), False, False, 3000000)
  608. w.Open()
  609. #may change duration into t.info.duration
  610. for n in range(int(t.info.fps)*int(head_duration+main_timer+ED_duration)):
  611. f=t.GetFrame(n)
  612. w.WriteFrame(f)
  613. t.Close()
  614. w.Close()
  615. print("Raw Video done")
  616. print("video at : www.choozmo.com:8168/"+name_hash+".mp4")
  617. progress = 100
  618. ws.send(progress)
  619. #line notifs
  620. #notify_group(name+"的影片已經產生完成囉! www.choozmo.com:8168/"+name_hash+".mp4")