main.py 25 KB

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