import requests import copy 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 + f"/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 + f"/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 + f"/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