main.py 24 KB

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