#!/usr/bin/env python3
from pathlib import Path
import urllib.parse,urllib.request,subprocess,json,hashlib,datetime
R=Path('/data/video-pipeline/HaTramAudio/project/026-Ngay-Chung-Ta-Xoa-Ten-Khoi-Giay-Dang-Ky-Ket-Hon');END='http://192.168.40.32:7861/voice/ngoc-huyen-clone';TEXT='Các bạn đang nghe truyện được phát từ Hạ Trâm Audio, chúc các bạn có những giây phút nghe truyện vui vẻ. Hãy ủng hộ chúng tôi bằng cách like video và đăng ký kênh.'
def sha(p):
 h=hashlib.sha256()
 with p.open('rb') as f:
  for b in iter(lambda:f.read(8<<20),b''):h.update(b)
 return h.hexdigest()
a=R/'audio';a.mkdir(exist_ok=True);voice=a/'intro-voice.wav';tmp=voice.with_suffix('.wav.tmp');data=urllib.parse.urlencode({'text':TEXT,'style':'doc_truyen','speed':'1.0','denoise':'true'}).encode();req=urllib.request.Request(END,data=data,method='POST',headers={'Content-Type':'application/x-www-form-urlencoded'});tmp.write_bytes(urllib.request.urlopen(req,timeout=600).read());tmp.replace(voice)
sil=a/'intro-silence-2s.wav';subprocess.run(['ffmpeg','-y','-v','error','-f','lavfi','-i','anullsrc=r=48000:cl=mono','-t','2','-c:a','pcm_s16le',str(sil)],check=True);lst=R/'work/tts/intro.ffconcat';lst.write_text(f"ffconcat version 1.0\nfile '{voice}'\nfile '{sil}'\n");full=a/'intro-full.wav';subprocess.run(['ffmpeg','-y','-v','error','-f','concat','-safe','0','-i',str(lst),'-c:a','pcm_s16le','-ar','48000','-ac','1',str(full)],check=True);dur=float(json.loads(subprocess.check_output(['ffprobe','-v','error','-show_entries','format=duration','-of','json',str(full)]))['format']['duration']);out=R/'output/intro/intro.mp4';out.parent.mkdir(parents=True,exist_ok=True);poster=R/'image/normalized/intro-poster-1920x1080.png';subprocess.run(['ffmpeg','-y','-v','error','-loop','1','-i',str(poster),'-i',str(full),'-t',str(dur),'-c:v','libx264','-preset','medium','-crf','18','-pix_fmt','yuv420p','-r','30','-c:a','aac','-b:a','192k','-movflags','+faststart',str(out)],check=True);vd=float(json.loads(subprocess.check_output(['ffprobe','-v','error','-show_entries','format=duration','-of','json',str(out)]))['format']['duration']);assert abs(vd-dur)<=1/30+0.01
rec={'schema_version':1,'project_id':'026','run_id':'run-20260722T033406Z-3df8cc80','status':'completed','verified':True,'text':TEXT,'voice_sha256':sha(voice),'silence_seconds':2.0,'audio_sha256':sha(full),'duration_seconds':dur,'video_path':str(out.relative_to(R)),'video_sha256':sha(out),'video_duration_seconds':vd,'poster_sha256':sha(poster),'created_at':datetime.datetime.now(datetime.timezone.utc).isoformat()};(R/'script/intro-receipt.json').write_text(json.dumps(rec,ensure_ascii=False,indent=2)+'\n');print(json.dumps({'status':'completed','duration':vd,'sha256':sha(out)}))
