main.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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= content
  271. draw.text((5,5), text, (255, 255, 255), font)
  272. canvas.save(save_target, "PNG")
  273. def txt2image_title(content, save_target):
  274. unicode_text = content
  275. font = ImageFont.truetype("font.ttf", 40,encoding='big5')
  276. text_width, text_height = font.getsize(unicode_text)
  277. canvas = Image.new('RGBA', (500, 500), (255, 0, 0, 0) )
  278. draw = ImageDraw.Draw(canvas)
  279. text=''
  280. for c in unicode_text:
  281. if len(re.findall(r'[\u4e00-\u9fff]+', c))>0:
  282. text+=myunichchar(c)
  283. else:
  284. text+=c
  285. draw.text((5,5), text, (0, 0, 0), font)
  286. canvas.save(save_target, "PNG")
  287. def call_achor_video_v2(fileName):
  288. conn = rpyc.classic.connect("192.168.1.105",18812)
  289. ros = conn.modules.os
  290. rsys = conn.modules.sys
  291. fr=open(dir_sound+fileName+".mp3",'rb')# voice
  292. #warning!!! file my be replaced by other process
  293. fw=conn.builtins.open('/tmp/output.mp3','wb')
  294. while True:
  295. b=fr.read(1024)
  296. if b:
  297. fw.write(b)
  298. else:
  299. break
  300. fr.close()
  301. fw.close()
  302. val=random.randint(1000000,9999999)
  303. ros.chdir('/home/jared/to_video')
  304. ros.system('./p6.sh '+str(val)+' &')
  305. while True:
  306. print('waiting...')
  307. if ros.path.exists('/tmp/results/'+str(val)):
  308. break
  309. time.sleep(5)
  310. print('waiting...')
  311. fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
  312. fw=open(dir_anchor+fileName+".mp4",'wb')#peggy1_1
  313. while True:
  314. b=fr.read(1024)
  315. if b:
  316. fw.write(b)
  317. else:
  318. break
  319. fr.close()
  320. fw.close()
  321. def call_achor_video(name):
  322. conn = rpyc.classic.connect("192.168.1.105",18812)
  323. ros = conn.modules.os
  324. rsys = conn.modules.sys
  325. fr=open(dir_sound+name+".mp3",'rb')# voice
  326. #warning!!! file my be replaced by other process
  327. fw=conn.builtins.open('/tmp/output.mp3','wb')
  328. while True:
  329. b=fr.read(1024)
  330. if b:
  331. fw.write(b)
  332. else:
  333. break
  334. fr.close()
  335. fw.close()
  336. val=random.randint(1000000,9999999)
  337. ros.chdir('/home/jared/to_video')
  338. ros.system('./p6.sh '+str(val)+' &')
  339. while True:
  340. print('waiting...')
  341. if ros.path.exists('/tmp/results/'+str(val)):
  342. break
  343. time.sleep(15)
  344. print('waiting...')
  345. fr=conn.builtins.open('/tmp/results/'+str(val)+'.mp4','rb')
  346. fw=open(dir_anchor+name+'.mp4','wb')#peggy1_1
  347. while True:
  348. b=fr.read(1024)
  349. if b:
  350. fw.write(b)
  351. else:
  352. break
  353. fr.close()
  354. fw.close()
  355. print('called............................................')
  356. def generate_subtitle_image(name_hash,text_content):
  357. sub_len = 10
  358. img_list = [None]*len(text_content)
  359. for idx in range(len(text_content)):
  360. img_list[idx] = []
  361. for step in range(math.ceil(len(text_content[idx])/sub_len)):
  362. sv_path = dir_subtitle + name_hash +'/'+str(idx)+ str(step) +'.png'
  363. sub = text_content[idx][step*sub_len:step*sub_len+sub_len]
  364. txt2image(sub, sv_path)
  365. img_list[idx] += [{"count":len(sub),"path":sv_path}]
  366. print(sub+':'+sv_path)
  367. return img_list
  368. def anchor_video(name,text_content, image_urls):
  369. m = hashlib.md5()
  370. m.update(name.encode("utf-8"))
  371. name_hash = m.hexdigest()
  372. file_prepare(name, name_hash, text_content,image_urls)
  373. call_achor_video(name_hash)
  374. ck=cKey(0,254,0,150)
  375. ck_anchor=cKey(0,255,1,320)
  376. duration = 0
  377. current_time = 0
  378. current_time_photo = 0
  379. #average layer level is 3
  380. t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO)
  381. t.Open()
  382. bg_head = openshot.FFmpegReader(dir_video+"bg_head.avi")
  383. bg_head.Open()
  384. bg_head_clip = video_photo_clip(vid=bg_head,layer=2,position=current_time,end=bg_head.info.duration,ck=ck)
  385. t.AddClip(bg_head_clip)
  386. LOGO_OP = openshot.FFmpegReader(dir_video+"LOGO_OP.mp4")
  387. LOGO_OP.Open() # Open the reader
  388. LOGO_OP_clip = video_photo_clip(vid=LOGO_OP,layer=4,position=current_time,end=bg_head.info.duration
  389. ,location_y=-0.03,scale_x=0.8,scale_y=0.71)
  390. t.AddClip(LOGO_OP_clip)
  391. duration+=bg_head.info.duration
  392. current_time += bg_head.info.duration
  393. current_time_photo += bg_head.info.duration
  394. sound = openshot.FFmpegReader(dir_sound+name_hash+".mp3")
  395. sound.Open()
  396. sound_clip = openshot.Clip(sound)
  397. sound_clip.Position(current_time)
  398. t.AddClip(sound_clip)
  399. duration += sound.info.duration
  400. bg = openshot.FFmpegReader(dir_video+"bg.mp4")
  401. bg.Open()
  402. bg_times = math.floor(sound.info.duration/bg.info.duration)
  403. left_time = sound.info.duration % bg.info.duration
  404. bg_clip_list = [None] * bg_times
  405. bg_list = [None] * bg_times
  406. bg.Close()
  407. for idx in range(bg_times):
  408. bg_list[idx] = openshot.FFmpegReader(dir_video+"bg.mp4")
  409. bg_list[idx].Open()
  410. bg_clip_list[idx] = video_photo_clip(bg_list[idx],layer=2,position=current_time
  411. ,end=bg_list[idx].info.duration,ck=ck)
  412. t.AddClip(bg_clip_list[idx])
  413. current_time += bg_list[idx].info.duration
  414. bg_list[idx].Close()
  415. bg_left = openshot.FFmpegReader(dir_video+"bg.mp4")
  416. bg_left.Open()
  417. bg_left_clip = video_photo_clip(bg_left,layer=2,position=current_time,end=left_time,ck=ck)
  418. t.AddClip(bg_left_clip)
  419. current_time += left_time
  420. bg_left.Close()
  421. p_num = len(listdir(dir_photo+name_hash))
  422. photo_clip_list = [None]*p_num
  423. img_list = [None]*p_num
  424. photo_idx = 0
  425. photo_duration = sound.info.duration/p_num
  426. for p in listdir(dir_photo+name_hash):
  427. img_list[photo_idx] = openshot.QtImageReader(dir_photo+name_hash+'/'+p)
  428. photo_clip_list[photo_idx] = video_photo_clip(vid=img_list[photo_idx],layer=3
  429. ,scale_x=0.81,scale_y=0.68,location_y=-0.03,position=current_time_photo,end=photo_duration
  430. ,audio=False)
  431. t.AddClip(photo_clip_list[photo_idx])
  432. current_time_photo+=photo_duration
  433. photo_idx+=1
  434. current_time_anchor = bg_head.info.duration
  435. anchor = openshot.FFmpegReader(dir_anchor+name_hash+".mp4")
  436. anchor.Open()
  437. anchor_times = math.floor(sound.info.duration/anchor.info.duration)
  438. left_time = sound.info.duration % anchor.info.duration
  439. anchor_clip_list = [None] * anchor_times
  440. anchor_list = [None] * anchor_times
  441. anchor.Close()
  442. for idx in range(anchor_times):
  443. anchor_list[idx] = openshot.FFmpegReader(dir_anchor+name_hash+".mp4")
  444. anchor_list[idx].Open()
  445. anchor_clip_list[idx] = video_photo_clip(vid=anchor_list[idx],layer=4,scale_x=0.65,scale_y=0.65,
  446. location_x=0.35,location_y=0.25,position=current_time_anchor, end=anchor_list[idx].info.duration,
  447. ck=ck_anchor,audio=False)
  448. t.AddClip(anchor_clip_list[idx])
  449. current_time_anchor += anchor_list[idx].info.duration
  450. anchor_list[idx].Close()
  451. anchor = openshot.FFmpegReader(dir_anchor+"peggy1_1.mp4")
  452. anchor.Open()
  453. 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
  454. , position=current_time_anchor,end=left_time,ck=ck_anchor)
  455. t.AddClip(anchor_left_clip)
  456. anchor.Close()
  457. title = openshot.QtImageReader(dir_title+name_hash+".png")
  458. title.Open() # Open the reader
  459. title_clip = video_photo_clip(vid=title, layer=4, location_y=0.9,position=0,end=duration)
  460. t.AddClip(title_clip)
  461. ####start building
  462. w = openshot.FFmpegWriter("../html/"+name_hash+".mp4")
  463. w.SetAudioOptions(True, "libmp3lame", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
  464. w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
  465. openshot.Fraction(1, 1), False, False, 3000000)
  466. w.Open()
  467. #may change duration into t.info.duration
  468. for n in range(int(t.info.fps)*int(duration)):
  469. f=t.GetFrame(n)
  470. w.WriteFrame(f)
  471. t.Close()
  472. w.Close()
  473. sound.Close()
  474. print("It's fine")
  475. notify_group(name+"的影片已經產生完成囉! www.choozmo.com:8168/"+name_hash+".mp4")
  476. def anchor_video_v2(name,text_content, image_urls):
  477. m = hashlib.md5()
  478. m.update(name.encode("utf-8"))
  479. name_hash = m.hexdigest()
  480. print('sub image made')
  481. file_prepare_v2(name, name_hash, text_content,image_urls)
  482. sub_list=generate_subtitle_image(name_hash,text_content)
  483. for fname in range(len(text_content)):
  484. call_achor_video_v2(name_hash+"/"+str(fname))
  485. print('step finish')
  486. print('called............................................')
  487. ck=cKey(0,254,0,150)
  488. ck_anchor=cKey(0,255,1,320)
  489. duration = 0
  490. #average layer level is 3
  491. t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO)
  492. t.Open()
  493. main_timer = 0
  494. LOGO_OP = openshot.FFmpegReader(dir_video+"LOGO_OP.mp4")
  495. LOGO_OP.Open() # Open the reader
  496. LOGO_OP_clip = video_photo_clip(vid=LOGO_OP,layer=4,position=0,end=LOGO_OP.info.duration
  497. ,location_y=-0.03,scale_x=0.8,scale_y=0.71)
  498. t.AddClip(LOGO_OP_clip)
  499. bg_head = openshot.FFmpegReader(dir_video+"bg_head.avi")
  500. bg_head.Open()
  501. bg_head_clip = video_photo_clip(vid=bg_head,layer=2,position=0,end=LOGO_OP.info.duration,ck=ck)
  502. t.AddClip(bg_head_clip)
  503. main_timer += LOGO_OP.info.duration
  504. head_duration = LOGO_OP.info.duration
  505. bg_head.Close()
  506. LOGO_OP.Close()
  507. clip_duration=0
  508. photo_clip_list = [None]*len(text_content)
  509. img_list = [None]*len(text_content)
  510. anchor_clip_list = [None] * len(text_content)
  511. anchor_list = [None] * len(text_content)
  512. audio_clip_list = [None] * len(text_content)
  513. audio_list = [None] * len(text_content)
  514. sub_clip_list = [None] * len(text_content)
  515. sub_img_list = [None] * len(text_content)
  516. idx = 0
  517. #mp4 also
  518. for p in listdir(dir_photo+name_hash):
  519. anchor_list[idx] = openshot.FFmpegReader(dir_anchor+name_hash+"/"+str(idx)+".mp4")
  520. clip_duration = anchor_list[idx].info.duration-0.3
  521. anchor_list[idx].Open()
  522. anchor_clip_list[idx] = video_photo_clip(vid=anchor_list[idx],layer=4,scale_x=0.65,scale_y=0.65,
  523. location_x=0.35,location_y=0.25,position=main_timer, end=clip_duration,ck=ck_anchor,audio=False)
  524. t.AddClip(anchor_clip_list[idx])
  525. img_list[idx] = openshot.FFmpegReader(dir_photo+name_hash+'/'+p)
  526. img_list[idx].Open()
  527. photo_clip_list[idx] = video_photo_clip(vid=img_list[idx],layer=3
  528. ,scale_x=0.81,scale_y=0.68,location_y=-0.03,position=main_timer,end=clip_duration,audio=False)
  529. t.AddClip(photo_clip_list[idx])
  530. img_list[idx].Close()
  531. audio_list[idx] = openshot.FFmpegReader(dir_sound+name_hash+"/"+str(idx)+".mp3")
  532. audio_list[idx].Open()
  533. audio_clip_list[idx] = openshot.Clip(audio_list[idx])
  534. audio_clip_list[idx].Position(main_timer)
  535. audio_clip_list[idx].End(clip_duration)
  536. t.AddClip(audio_clip_list[idx])
  537. img_list[idx].Close()
  538. anchor_list[idx].Close()
  539. audio_list[idx].Close()
  540. sub_img_list[idx] = [None] * len(sub_list[idx])
  541. sub_clip_list[idx] = [None] * len(sub_list[idx])
  542. sub_timer = 0
  543. for sub_idx in range(len(sub_list[idx])):
  544. sub_img_list[idx][sub_idx] = openshot.QtImageReader(sub_list[idx][sub_idx]['path'])
  545. sub_img_list[idx][sub_idx].Open()
  546. sub_duration = 0.275*sub_list[idx][sub_idx]['count']
  547. sub_clip_list[idx][sub_idx] = video_photo_clip(vid=sub_img_list[idx][sub_idx], layer=5, location_y=0.88,position=main_timer+sub_timer,end=sub_duration)
  548. t.AddClip(sub_clip_list[idx][sub_idx])
  549. sub_img_list[idx][sub_idx].Close()
  550. sub_timer += sub_duration
  551. print(sub_list[idx][sub_idx]['path'])
  552. main_timer += clip_duration
  553. idx+=1
  554. LOGO_ED = openshot.FFmpegReader(dir_video+"LOGO_ED.avi")
  555. LOGO_ED.Open()
  556. LOGO_ED_clip = video_photo_clip(vid=LOGO_ED,layer=4,position=main_timer,end=LOGO_ED.info.duration
  557. ,location_y=-0.03,scale_x=0.8,scale_y=0.71)
  558. t.AddClip(LOGO_ED_clip)
  559. ED_duration = LOGO_ED.info.duration
  560. LOGO_ED.Close()
  561. bg = openshot.FFmpegReader(dir_video+"bg.mp4")
  562. bg.Open()
  563. bg_times = math.floor(main_timer+ED_duration/bg.info.duration)
  564. left_time = (main_timer+ED_duration) % bg.info.duration
  565. bg_clip_list = [None] * bg_times
  566. bg_list = [None] * bg_times
  567. bg.Close()
  568. bg_timer = head_duration
  569. for idx in range(bg_times):
  570. bg_list[idx] = openshot.FFmpegReader(dir_video+"bg.mp4")
  571. bg_list[idx].Open()
  572. bg_clip_list[idx] = video_photo_clip(bg_list[idx],layer=2,position=bg_timer
  573. ,end=bg_list[idx].info.duration,ck=ck)
  574. t.AddClip(bg_clip_list[idx])
  575. bg_timer += bg_list[idx].info.duration
  576. bg_list[idx].Close()
  577. bg_left = openshot.FFmpegReader(dir_video+"bg.mp4")
  578. bg_left.Open()
  579. bg_left_clip = video_photo_clip(bg_left,layer=2,position=bg_timer,end=left_time,ck=ck)
  580. t.AddClip(bg_left_clip)
  581. bg_left.Close()
  582. title = openshot.QtImageReader(dir_title+name_hash+".png")
  583. title.Open() # Open the reader
  584. title_clip = video_photo_clip(vid=title, layer=4, location_y=0.8,position=0,end=head_duration+main_timer)
  585. t.AddClip(title_clip)
  586. ####start building
  587. w = openshot.FFmpegWriter("../html/"+name_hash+".mp4")
  588. w.SetAudioOptions(True, "libmp3lame", 44100, 2, openshot.LAYOUT_STEREO, 3000000)
  589. w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720,
  590. openshot.Fraction(1, 1), False, False, 3000000)
  591. w.Open()
  592. #may change duration into t.info.duration
  593. for n in range(int(t.info.fps)*int(head_duration+main_timer+ED_duration)):
  594. f=t.GetFrame(n)
  595. w.WriteFrame(f)
  596. t.Close()
  597. w.Close()
  598. print("Raw Video done")
  599. print("video at : www.choozmo.com:8168/"+name_hash+".mp4")
  600. #line notifs
  601. notify_group(name+"的影片已經產生完成囉! www.choozmo.com:8168/"+name_hash+".mp4")