import aiohttp.web, asyncio, urllib.parse, pathlib, builtins, numpy, io, sys, math, os, uvloop, lxml.etree, PIL.Image, re, json, av, itertools, datetime, uuid, hashlib, email.policy, fake_useragent, huggingface_hub, time, traceback
from modelscope.hub.api import HubApi

# use chatgpt to create narration say limit to 55 to 65 chinese characters
scripts = [

    #chapter 1
    {
        "narration": "当地时间十二月十三日下午，布朗大学一栋教学楼内发生枪击事件，枪声打破平静后现场随即展开封锁与应急处置。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "事发时恰逢期末考试高峰，多间教室人员集中突发状况导致考试中断师生紧急避险并启动校内安全流程展开自救与撤离。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "校方接报后立即发布紧急通知通过广播与短信提醒师生就地避难锁门等待后续指引并迅速与地方部门对接信息通报机制。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "普罗维登斯警方迅速抵达现场并在校区多处设立警戒线封锁出入口以便开展取证排查并维护现场秩序保障师生安全。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "救护力量第一时间集结对受伤者实施分类急救并将重伤者分批转运至附近医院医疗团队同步启动创伤救治预案展开救治工作。",
        "prompt": "白天，日光，柔光，中景，中心构图，医院急诊口与救护车近景，医护人员搬运担架、检查伤者，设备与走廊动作连续清晰可见。"
    },
    {
        "narration": "警方与校方对涉案楼层逐一排查侦查人员采集弹壳指纹与监控资料以便通过技术手段还原时间线与追查可能的行踪线索。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "校方宣布暂停剩余期末考试并设立心理支援站为受影响学生与教职工提供紧急心理干预与后续随访与学业安排支持服务。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "志愿者与学生组织自发行动在避难点提供热饮毯子與物资并协助家属沟通学校与社区合力提供后勤保障与临时安置安排。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "事发消息通过社交媒体快速传播校方与执法单位呼吁以官方通告为准并提醒公众不要转发未经核实的影像与不实消息。",
        "prompt": "白天，日光，柔光，中景，中心构图，校园广场或门口全景，警车与人员排列，校徽与建筑可辨，画面稳重便于后期叙事。"
    },
    {
        "narration": "此次枪击事件在校园内外引起广泛关注校方与地方机构承诺全力协助调查并为遇难者與伤者家属提供必要的支持與善后安排。",
        "prompt": "白天，日光，柔光，中景，中心构图，校园广场或门口全景，警车与人员排列，校徽与建筑可辨，画面稳重便于后期叙事。"
    },

    #chapter 2
    {
        "narration": "警方对现场实施封存并组织技术侦查人员采集弹壳血迹与周边痕迹同时调取监控以构建时间线还原案发经过与涉事人员轨迹。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "校方与地方政府成立联络小组统一信息发布并协调救援资源同时对家属提供专门联络窗口以便及时通报伤者与处理后续事宜。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "医院通报已接收多名伤者医疗团队夜以继日开展救治部分伤者进入手术与监护程序医院同時公布探视与信息通报规范。",
        "prompt": "白天，日光，柔光，中景，中心构图，医院急诊口与救护车近景，医护人员搬运担架、检查伤者，设备与走廊动作连续清晰可见。"
    },
    {
        "narration": "校园部分路段采取临时交通管制出入口设置检查点对进出人员与车辆进行核验以确保救援通道畅通并维护现场秩序与安全。",
        "prompt": "白天，日光，柔光，中景，中心构图，校园广场或门口全景，警车与人员排列，校徽与建筑可辨，画面稳重便于后期叙事。"
    },
    {
        "narration": "警方公布若干监控画面片段并请求公众协助辨认知情者被请保存相关录像与证据以便与调查人员取得联系提供可用线索。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "在避难与疏散过程中部分学生出现轻伤或惊恐反应学校与志愿者在避难点提供急救与心理安抚并记录受助人员以便后续跟进。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "警方与校方再次提醒师生遵守安全流程不要返回危险区域并密切关注官方通告以免二次伤害同时配合调查工作保障公共安全。",
        "prompt": "白天，日光，柔光，中景，中心构图，校园广场或门口全景，警车与人员排列，校徽与建筑可辨，画面稳重便于后期叙事。"
    },
    {
        "narration": "周边社区加强巡逻并开展协查警员与居民沟通请商家保存监控录像以便提供可能的目击证据协助调查人员复原嫌疑人逃离路线。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "志愿组织在现场设立临时帐篷提供食品與物资并协助校方进行登记与安置工作确保避难学生能够得到基本生活照顾与信息传达渠道。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "记者在现场设立临时采访区按照官方通告核实信息进行采访报道媒体强调以权威通报为准并避免传播未经核验的猜测性内容。",
        "prompt": "白天，日光，柔光，中景，中心构图，校园广场或门口全景，警车与人员排列，校徽与建筑可辨，画面稳重便于后期叙事。"
    },

    #chapter 3
    {
        "narration": "校方表示将优先照顾伤者與遇难者家属协调医疗探视與生活安置并在尊重隐私前提下向公众通报经核实的信息与善后安排。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "心理健康中心增派专业人员设立咨询点为受影响学生與教职工提供危机干预并安排后续随访与康复支持以缓解心理创伤影响。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "警方对监控资料与电子记录进行逐条比对侦查人员按时间线还原现场画面以查明嫌疑人行踪并汇总关键证据提交技术鉴定。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "学生自治与校友团体发表声明呼吁冷静理性并组织募捐与支援行动协助受影响学生与家庭渡过紧急时期提供必要的物资与心理支持。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "地方教育主管部门将与校方会商评估校园安防体系提出改进方案包括拓展监控覆盖提升巡逻频率与完善紧急通报与疏散演练机制建议。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "教务处表示将与师生协商学业与考试安排提供补考或延期选项以兼顾学业公平与受影响学生的心理康复与休整需要安排。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "法律援助与社区服务机构为受害者家属提供咨询協助办理手续并在必要时提供法律援助与权益维护帮助处理善后相关法律事务。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "校园内悼念活动在指定场所有序进行师生与居民献花默哀学校组织心理关怀与纪念安排为伤者家属提供慰问渠道與支持。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "法医与弹道专家对现场弹壳與射击轨迹进行鉴定以便确认射击位置与枪械类型为侦查提供技术依据并支撑后续的司法程序。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "校方公布临时联络热线与信息平台方便家属查询伤者近况并安排探视交通与心理支持确保信息渠道通畅与支援能够及时到位。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },

    #chapter 4
    {
        "narration": "警方公布部分监控影像并请求公众辨认相关人物与时间线同时提醒知情公众保存可疑时段录像以便与调查人员取得联系提供线索。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "执法单位定期在媒体面前通报调查进展回应公众关切并在保证调查公正的同时采取措施保护受害者與证人隐私与安全。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "警方对周边可疑车辆与停车记录展开比对调取电子证据并通过时间线拼接与轨迹分析以寻找嫌疑人可能的逃离路线与藏身地点。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "校方与执法机关在通报时强调将依法保护受害者與证人隐私任何个人信息的公布将遵循程序并提前通知家属以保障尊严與安全。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "社区与专家围绕校园安全召开座谈提出多项改善建议包括强化出入口管理增设监控与开展常态化应急训练以提升整体预警与响应能力。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "校方承诺将审视并提升校园安防措施包括增配安保人员完善监控覆盖与改进紧急通报系统同时研究技术化手段提高快速响应效率。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "警方呼吁商家與居民保存事发时段录像并配合调查调查组将在保护隐私前提下核实信息任何细微线索均可能成为破案关键。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "校内志愿者与社团持续为避难学生提供热食衣物与心理陪伴并协助协调交通与临时住宿确保受影响人员得到及时的生活支援与关怀。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "研究者與专业人士被邀请参与校园安全评估提出制度化建议包括风险评估机制应急培训与学术支持用于长期预防与干预策略研究。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "司法部门表示将依法推进后续程序任何起诉与证据提交均会遵循法定流程以确保证据链完整并维护司法公正与程序透明。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },

    #chapter 5
    {
        "narration": "罗德岛地区医院通报接收多名伤者医疗团队连夜开展创伤救治并进行康复评估以安排阶段性手术与后续康复治疗与护理。",
        "prompt": "白天，日光，柔光，中景，中心构图，医院急诊口与救护车近景，医护人员搬运担架、检查伤者，设备与走廊动作连续清晰可见。"
    },
    {
        "narration": "校方设立家属联络小组统一通报伤者病情并协助办理探视交通与心理法律支援确保家属及时获取信息并得到必要的后勤与情感支持。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "校友與社会组织发起募捐与支援活动筹措资源协助伤者家庭与受影响学生提供临时住宿法律援助與生活物资等实际支持与后续安排。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "媒体在核实官方通告后开展持续监督报道强调证据与司法程序的透明公众被提醒以权威信息为准避免传播未经证实的猜测性内容。",
        "prompt": "白天，日光，柔光，中景，中心构图，校园广场或门口全景，警车与人员排列，校徽与建筑可辨，画面稳重便于后期叙事。"
    },
    {
        "narration": "当局强调将保护提供线索者隐私并提供必要保护措施鼓励公众通过官方渠道举报可疑信息以便调查组快速核查与反馈处理线索。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "校方表示将全面检视安防体系包括监控覆盖出入口管理與巡逻安排并研究引入技术手段提升预警与快速响应能力以减少类似风险。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "社区与高校举行公开座谈讨论校园安全在尊重隐私与权利前提下提出具体改进建议并形成可操作的应急预案与社区支援网络方案。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "救援與志愿团队的专业协作受到关注相关报道记录他们在现场分工调配与物资发放的细节以反映紧急响应的组织效率与执行过程。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "校方制定长期支援计划包括持续心理康复学业安排调整與对受害家庭的长期援助承诺并将在近期公布具体资源配置與实施时间表。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "随着调查推进警方会依法公布后续进展并反复提醒公众以官方通报为准避免谣言干扰救援與司法程序以维护调查的严肃性与效率。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },

    #chapter 6
    {
        "narration": "未来数日调查人员将继续比对多路监控与证据链通过技术鉴定与时间线还原努力还原案发始末以寻找更多关键线索与证据支持。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "学校将与政府相关部门合作推进校园安全改革提升应急预警系统完善监控布局并加强师生安全教育以提高整体预防与应对能力。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "社区與校方组织募捐与支援网络以确保证受害者家庭在医疗生活與法律方面获得持续帮助并协调长期康复资源与支持措施。",
        "prompt": "白天，日光，柔光，中景，中心构图，避难点帐篷与志愿者分发物资场景，中景记录志愿者与学生互动、登记与物资摆放细节。"
    },
    {
        "narration": "教育主管部门将在适当时机公布校园安全制度改革的初步方向与实施时间表並邀请各方参与评估以确保方案可行有效。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "警方重申在未经核实前不会随意公布个人身份并承诺在信息披露前优先通知家属以尊重隐私并维护司法程序的严谨性与正当性。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "校园安全议题将延伸至全国教育系统层面专家與政策制定者将就预防机制應對策略與资源配置开展长期研究與跨部门对话。",
        "prompt": "白天，日光，柔光，中景，中心构图，社区会议或座谈会场景，专家与居民发言，投影屏与记录本细节被镜头捕捉，互动节奏可见。"
    },
    {
        "narration": "执法机关将在确保证据链完整前提下推进问讯與鉴定程序并依法律程序对相关嫌疑与责任进行调查与处理以维护司法正义。",
        "prompt": "白天，日光，柔光，中景，中心构图，警员在现场布控并采集证物，证据袋與标记特写，监控画面被放大比对，侦查动作细节可辨。"
    },
    {
        "narration": "校方表示将总结此次事件经验教训推进校园安全教育并在日常管理中强化突发事件演练以提升师生的自我保护与互助协作能力。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "校园哀悼與守夜活动将在指定场所有序进行学校将设立纪念空间并组织悼念与关怀活动为遇难者与其家属提供悼念渠道与情感支持。",
        "prompt": "白天，日光，柔光，中景，中心构图，教学楼与走廊近景，窗外光线透入，桌椅与散落试卷细节可见，学生避险或医护行动被镜头记录。"
    },
    {
        "narration": "我们将持续跟踪调查与救援进展并在官方权威信息发布后第一时间整理核实内容向公众公布以便社会了解事实并推动必要的问责与改进。",
        "prompt": "白天，日光，柔光，中景，中心构图，校园广场或门口全景，警车与人员排列，校徽与建筑可辨，画面稳重便于后期叙事。"
    }
]

token = '6A5AA1D4EAFF4E9FB37E23D68491D6F4'

def XTimestamp(): return datetime.datetime.now(datetime.timezone.utc).strftime('%a %b %d %Y %H:%M:%S GMT+0000 (Coordinated Universal Time)')

def sec_ms_gec():
    ticks = datetime.datetime.now(datetime.timezone.utc).timestamp()
    ticks += 11644473600
    ticks -= ticks % 300
    ticks *= 1e9 / 100
    str_to_hash = f'{ticks:.0f}' + token
    return hashlib.sha256(str_to_hash.encode()).hexdigest().upper()

speak = lxml.etree.Element('speak', version='1.0', xmlns='http://www.w3.org/2001/10/synthesis', attrib={'{http://www.w3.org/XML/1998/namespace}lang':'zh-CN'})
voice = lxml.etree.SubElement(speak, 'voice', name='Microsoft Server Speech Text to Speech Voice (zh-CN, XiaoxiaoNeural)')

async def edge(prompt):
    #https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts
    voice.text = prompt
    result = []
    userAgent = fake_useragent.UserAgent(platforms='desktop').edge
    async with aiohttp.ClientSession(headers={'user-agent':userAgent}) as client:
        async with client.ws_connect('wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1', params={'TrustedClientToken':token ,'ConnectionId':builtins.str(uuid.uuid4()).replace('-', ''), 'Sec-MS-GEC':sec_ms_gec(), 'Sec-MS-GEC-Version':'1-' + re.search(r'Chrome/([\d.]+)', userAgent).group(1)}) as websocket:
            message = email.message.EmailMessage(policy=email.policy.HTTP)
            message.add_header('X-Timestamp', XTimestamp())
            message.add_header('Content-Type', 'application/json; charset=utf-8')
            message.add_header('Path', 'speech.config')
            await websocket.send_str(message.as_string() + json.dumps({'context':{'synthesis':{'audio':{'outputFormat':'audio-24khz-48kbitrate-mono-mp3'}}}}))
            message = email.message.EmailMessage(policy=email.policy.HTTP)
            message.add_header('X-RequestId', builtins.str(uuid.uuid4()).replace('-', ''))
            message.add_header('Content-Type', 'application/ssml+xml')
            message.add_header('X-Timestamp', XTimestamp() + 'Z')  # This is not a mistake, Microsoft Edge bug.
            message.add_header('Path', 'ssml')
            await websocket.send_str(message.as_string() + lxml.etree.tostring(speak).decode())
            async for _ in websocket:
                if _.type == aiohttp.WSMsgType.TEXT:
                    if email.message_from_string(_.data).get('Path') == 'turn.end':break
                if _.type == aiohttp.WSMsgType.BINARY: result += _.data[builtins.int.from_bytes(_.data[:2]) + 2:],
    return b''.join(result)

async def google(prompt):
    async with aiohttp.ClientSession(headers={'user-agent':fake_useragent.UserAgent().chrome}) as client:
        async with client.get('https://translate.google.com/translate_tts', params={'ie':'UTF-8', 'q':prompt, 'tl':'zh-CN', 'client':'tw-ob'}) as _: return await _.content.read()

async def main():
    app = aiohttp.web.Application()
    app.add_routes([aiohttp.web.static('/', pathlib.Path(__file__).resolve().parent, show_index=True)])
    runner = aiohttp.web.AppRunner(app)
    await runner.setup()
    site = aiohttp.web.TCPSite(runner, port=7860)
    await site.start()
    async with aiohttp.ClientSession(headers={'authorization':'Bearer ' + os.getenv('modelscope')}, timeout=aiohttp.ClientTimeout()) as client:
        zh = 'https://chaowenguo-zh.ms.show/'
        async with client.post(urllib.parse.urljoin(zh, 'imageStart'), json={'prompt':scripts[0].get('prompt'), 'height':720, 'width':1280}) as _:pass
        while True:
            async with client.get(urllib.parse.urljoin(zh, 'imageGet')) as qwen:
                print(qwen.status)
                if qwen.status == 404: await asyncio.sleep(60)
                else: 
                    buffer = io.BytesIO(await qwen.content.read())
                    image = PIL.Image.open(buffer)
                    with av.open('output.mp4', mode='w') as writer:
                        video = writer.add_stream('h264', rate=8)
                        video.height = image.size[1]
                        video.width = image.size[0]
                        video.pix_fmt = 'yuv420p'
                        videoPts = 0
                        audioPts = 0
                        audio = None
                        for index, (script, last) in builtins.enumerate(itertools.pairwise(scripts)):
                            outer = False
                            while True:
                                with aiohttp.MultipartWriter('form-data') as mpwriter:
                                    mpwriter.append(script.get('prompt')).set_content_disposition('form-data', name='prompt')
                                    mpwriter.append(last.get('prompt')).set_content_disposition('form-data', name='last')
                                    mpwriter.append(buffer.getvalue(), {'Content-Type':'image/png'}).set_content_disposition('form-data', name='image', filename='image.png')
                                    async with client.post(urllib.parse.urljoin(zh, 'videoStart'), data=mpwriter) as _: pass
                                    while True:
                                        try:
                                            async with client.get(urllib.parse.urljoin(zh, 'videoGet')) as get:
                                                print(get.status)
                                                match get.status:
                                                    case 404: await asyncio.sleep(60)
                                                    case 500 | 429: break
                                                    case 200:
                                                        reader = numpy.load(io.BytesIO(await get.content.read())).get('arr_0')
                                                        buffer.seek(0)
                                                        buffer.truncate(0)
                                                        PIL.Image.fromarray(reader[-1]).save(buffer, format='png')
                                                        with av.open(io.BytesIO(await sys.modules.get(__name__).edge(script.get('narration'))), format='mp3') as container:
                                                            if not audio: audio = writer.add_stream('aac', rate=container.streams.audio[0].rate)
                                                            speed = builtins.float(container.streams.audio[0].duration * container.streams.audio[0].time_base) / 10
                                                            print(speed)
                                                            graph = av.filter.Graph()
                                                            graph.link_nodes(graph.add_abuffer(template=container.streams.audio[0]), graph.add('atempo', builtins.str(speed)), graph.add('apad', 'whole_dur=10'), graph.add('atrim', '0:10'), graph.add('abuffersink')).configure()
                                                            frames = []
                                                            for frame in container.decode():
                                                                graph.push(frame)
                                                                while True:
                                                                    try: frames += graph.pull(),
                                                                    except (av.BlockingIOError, av.EOFError): break
                                                            for frame in frames:
                                                                frame.pts = audioPts
                                                                audioPts += frame.samples
                                                                writer.mux(audio.encode(frame))
                                                        graph = av.filter.Graph()
                                                        pathlib.Path(__file__).resolve().parent.joinpath('subtitle.ass').write_text(pathlib.Path(__file__).resolve().parent.joinpath('subtitle').read_text().replace('left', builtins.str(datetime.timedelta(seconds=index * 10))).replace('right', builtins.str(datetime.timedelta(seconds=(index + 1) * 10))).replace('prompt', script.get('narration').replace('，', '， ')))
                                                        graph.link_nodes(graph.add_buffer(height=video.height, width=video.width, format='rgb24', time_base=video.time_base), graph.add('subtitles', 'subtitle.ass'), graph.add('buffersink')).configure()
                                                        for _ in itertools.islice(reader, reader.shape[0] - 1):
                                                            frame = av.VideoFrame.from_ndarray(_)
                                                            frame.pts = videoPts
                                                            videoPts += video.time_base.denominator // video.average_rate
                                                            graph.push(frame)
                                                            while True:
                                                                try: writer.mux(video.encode(graph.pull()))
                                                                except (av.BlockingIOError, av.EOFError):break
                                                        graph.push(None)
                                                        while True:
                                                            try: writer.mux(video.encode(graph.pull()))
                                                            except (av.BlockingIOError, av.EOFError):break
                                                        outer = True
                                                        break
                                        except (aiohttp.ClientConnectionError, aiohttp.ClientPayloadError): break
                                    if outer: break
                        writer.mux(video.encode())
                        writer.mux(audio.encode())
                    break
        output = pathlib.Path(__file__).resolve().parent.joinpath('output.mp4').read_bytes()
        #async with client.post('https://oauth2.googleapis.com/token', json={'client_id':os.getenv('youtubeId'), 'client_secret':os.getenv('youtubeSecret'), 'refresh_token':os.getenv('refresh'), 'grant_type':'refresh_token'}) as token: 
        #    accessToken = (await token.json()).get('access_token')
        #    async with client.post('https://www.googleapis.com/upload/youtube/v3/videos', params={'uploadType':'resumable', 'part':'snippet,status'}, headers={'authorization':'Bearer ' + accessToken, 'X-Upload-Content-Type':'video/mp4', 'X-Upload-Content-Length':builtins.str(builtins.len(output))}, json={'snippet':{'title':'gorgeous', 'description':'gorgeous', 'tags':['gorgeous'], 'categoryId': 22}, 'status':{'privacyStatus':'public', 'selfDeclaredMadeForKids':False}}) as metadata: # can not use metadata.url because the metadata.status == 200 not 301 or 302 aiohttp will not redirect
        #        async with client.post(metadata.headers.get('Location'), headers={'authorization':'Bearer ' + accessToken}, data=output) as upload:
        #            async with client.post('https://www.googleapis.com/youtube/v3/playlistItems', params={'part':'snippet'}, headers={'authorization':'Bearer ' + accessToken}, json={'snippet':{'playlistId':'PLREwfQq2HDLcuyUDf0d3_t7ZIFnz6tK1x', 'resourceId':{'kind':'youtube#video', 'videoId':(await upload.json()).get('id')}}}) as _: pass
        async with client.post('https://api.dailymotion.com/oauth/token', data={'grant_type':'password', 'client_id':os.getenv('dailymotionId'), 'client_secret':os.getenv('dailymotionSecret'), 'scope':'manage_videos', 'username':'bill8bush', 'password':os.getenv('password')}) as token:
            accessToken = (await token.json()).get('access_token')
            async with client.get('https://api.dailymotion.com/file/upload', headers={'authorization':'Bearer ' + accessToken}) as upload:
                with aiohttp.MultipartWriter('form-data') as mpwriter:
                    mpwriter.append(output, {'Content-Type':'video/mp4'}).set_content_disposition('form-data', name='file', filename='video.mp4')
                    async with client.post((await upload.json()).get('upload_url'), headers={'authorization':'Bearer ' + accessToken}, data=mpwriter) as url:
                        async with client.post('https://api.dailymotion.com/user/x3f9ing/videos', headers={'authorization':'Bearer ' + accessToken}, data={'url':(await url.json()).get('url'), 'title':'Dailymotion upload test', 'channel':'news', 'published':'true', 'private':'false', 'is_created_for_kids':'false', 'description':'abv'}) as _: print(await _.json()) #https://developers.dailymotion.com/reference/video-categories 
    HubApi().upload_file(path_or_fileobj='output.mp4', path_in_repo='zh.mp4', repo_id='chaowenguo/wan', repo_type='dataset', token=os.getenv('modelscope'))
    await asyncio.sleep(math.inf)

try:
    uvloop.run(main())
except:
    pathlib.Path(__file__).resolve().parent.joinpath('zh.txt').write_text(traceback.format_exc())
    huggingface_hub.upload_file(path_or_fileobj='zh.txt', path_in_repo='zh.txt', repo_id='exact-railcar/wan', repo_type='dataset', token=os.getenv('huggingface'))
    time.sleep(math.inf)