import copy import requests CREATOMATE_API_KEY = "df9e4382d7e84fe790bf8a2168152be195d5a3568524ceb66ed989a2dea809f7d3065d6803b2e3dd9d02b5e5ec1c9823" # ACCOUNT_URL = "https://ado2mediastoragepublic.blob.core.windows.net/ado2-media-public-access/ado2-media-original/" # Creatomate 템플릿 정보 전부 가져오기 class Creatomate: base_url: str = "https://api.creatomate.com" def __init__(self, api_key): self.api_key = api_key def get_all_templates_data(self) -> dict: url = Creatomate.base_url + "/v1/templates" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}", } response = requests.get(url, headers=headers) return response.json() # Creatomate 템플릿 ID 로부터 해당 템플릿 정보 가져오기 def get_one_template_data(self, template_id: str) -> dict: url = Creatomate.base_url + f"/v1/templates/{template_id}" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}", } response = requests.get(url, headers=headers) return response.json() # 템플릿 정보 파싱하여 리소스 이름 추출하기 def parse_template_component_name(self, template_source: dict) -> dict: def recursive_parse_component(element: dict) -> dict: if "name" in element: result_element_name_type = {element["name"]: element["type"]} else: result_element_name_type = {} if element["type"] == "composition": minor_component_list = [ recursive_parse_component(minor) for minor in element["elements"] ] for minor_component in minor_component_list: ## WARNING : Same name component should shroud other component. be aware result_element_name_type.update(minor_component) return result_element_name_type result = {} for result_element_dict in [ recursive_parse_component(component) for component in template_source ]: result.update(result_element_dict) return result # 템플릿 정보 이미지/가사/음악 리소스와 매핑하기 # 이미지는 순차적으로 집어넣기 # 가사는 개행마다 한 텍스트 삽입 # Template에 audio-music 항목이 있어야 함. (추가된 템플릿 Cafe뿐임) def template_connect_resource_blackbox( self, template_id: str, image_url_list: list[str], lyric: str, music_url: str ) -> dict: template_data = self.get_one_template_data(template_id) template_component_data = self.parse_template_component_name( template_data["source"]["elements"] ) lyric.replace("\r", "") lyric_splited = lyric.split("\n") modifications = {} for idx, (template_component_name, template_type) in enumerate( template_component_data.items() ): match template_type: case "image": modifications[template_component_name] = image_url_list[ idx % len(image_url_list) ] case "text": modifications[template_component_name] = lyric_splited[ idx % len(lyric_splited) ] modifications["audio-music"] = music_url return modifications def elements_connect_resource_blackbox( self, elements: list, image_url_list: list[str], lyric: str, music_url: str ) -> dict: template_component_data = self.parse_template_component_name(elements) lyric.replace("\r", "") lyric_splited = lyric.split("\n") modifications = {} for idx, (template_component_name, template_type) in enumerate( template_component_data.items() ): match template_type: case "image": modifications[template_component_name] = image_url_list[ idx % len(image_url_list) ] case "text": modifications[template_component_name] = lyric_splited[ idx % len(lyric_splited) ] modifications["audio-music"] = music_url return modifications def modify_element(self, elements: list, modification: dict): def recursive_modify(element: dict) -> dict: if "name" in element: match element["type"]: case "image": element["source"] = modification[element["name"]] case "audio": element["source"] = modification.get(element["name"], "") case "video": element["source"] = modification[element["name"]] case "text": element["source"] = modification.get(element["name"], "") case "composition": for minor in element["elements"]: recursive_modify(minor) for minor in elements: recursive_modify(minor) return elements # Creatomate에 생성 요청 # response에 요청 정보 있으니 풀링 필요 def make_creatomate_call(self, template_id: str, modifications: dict): url = Creatomate.base_url + "/v2/renders" data = {"template_id": template_id, "modifications": modifications} headers = { "Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}", } response = requests.post(url, json=data, headers=headers) return response # Creatomate에 생성 요청 without template # response에 요청 정보 있으니 풀링 필요 def make_creatomate_custom_call(self, source: str): url = Creatomate.base_url + "/v2/renders" data = source headers = { "Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}", } response = requests.post(url, json=data, headers=headers) return response def calc_scene_duration(self, template: dict): total_template_duration = 0 for elem in template["source"]["elements"]: try: if elem["type"] == "audio": continue total_template_duration += elem["duration"] if "animations" not in elem: continue for animation in elem["animations"]: assert animation["time"] == 0 # 0이 아닌 경우 확인 필요 if animation["transition"]: total_template_duration -= animation["duration"] except: print(elem) return total_template_duration def extend_template_duration(self, template: dict, target_duration: float): template["duration"] = target_duration total_template_duration = self.calc_scene_duration(template) extend_rate = target_duration / total_template_duration new_template = copy.deepcopy(template) for elem in new_template["source"]["elements"]: try: if elem["type"] == "audio": continue elem["duration"] = elem["duration"] * extend_rate if "animations" not in elem: continue for animation in elem["animations"]: assert animation["time"] == 0 # 0이 아닌 경우 확인 필요 animation["duration"] = animation["duration"] * extend_rate except: print(elem) return new_template # Azure사용한 legacy 코드 원본 # def template_connect_resource_blackbox(template_id, user_idx, task_idx): # secret_client = get_keyvault_client() # account_url = secret_client.get_secret(BLOB_ACCOUNT_URL_KEY).value # media_folder_path = f"{user_idx}/{task_idx}" # lyric_path = f"{media_folder_path}/lyric.txt" # lyric = az_storage.az_storage_read_ado2_media(lyric_path).readall().decode('UTF-8') # media_list = az_storage.az_storage_get_ado2_media_list(media_folder_path) # image_list = [media.name for media in media_list if '/crawling-images/' in media.name] # template_data = get_one_template_data(template_id) # template_component_data = parse_template_component_name(template_data['source']['elements']) # lyric.replace("\r", "") # lyric_splited = lyric.split("\n") # modifications = {} # for idx, (template_component_name, template_type) in enumerate(template_component_data.items()): # match template_type: # case 'image': # modifications[template_component_name] = f"{account_url}/{BLOB_CONTAINER_NAME}/{image_list[idx % len(image_list)]}" # case 'text': # modifications[template_component_name] = lyric_splited[idx % len(lyric_splited)] # modifications["audio-music"] = f"{account_url}/{BLOB_CONTAINER_NAME}/{BLOB_MEDIA_FOLDER}/{media_folder_path}/music_mureka.mp3" # print(modifications) # return modifications