main.py 25 KB

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