import time import os import logging import re from pywinauto import Application, findwindows, clipboard, timings from pywinauto.controls.hwndwrapper import HwndWrapper # 로깅 설정 logging.basicConfig(level=logging.DEBUG, format="%(asctime)s [%(levelname)s] %(message)s") logger = logging.getLogger(__name__) class WhaleTranslator: def __init__(self): self.app = None self.whale_window = None self.hwnd_wrapper = None def start_whale_in_secret_mode(self): whale_exe_path = os.path.join(os.getcwd(), "browsers", "whale", "whale.exe") user_data_dir = os.path.join(os.getcwd(), "browsers", "whale", "user_data") cache_dir = os.path.join(os.getcwd(), "browsers", "whale", "cache") self.app = Application(backend="uia").start( f'"{whale_exe_path}" --incognito --user-data-dir="{user_data_dir}" --disk-cache-dir="{cache_dir}"' ) # 창이 완전히 생성될 때까지 대기 self.whale_window = self.find_whale_window() if self.whale_window: self.logger.info("웨일 시크릿 모드로 시작 완료.") else: self.logger.warning("웨일 창을 찾을 수 없습니다.") def find_whale_window(self): try: # 최대 10초 동안 '새 시크릿 탭 - Whale' 창이 나타나기를 기다림 timings.wait_until(10, 0.5, lambda: any(window.name == '새 시크릿 탭 - Whale' for window in findwindows.find_elements())) windows = findwindows.find_elements() for window in windows: if window.name == '새 시크릿 탭 - Whale': whale_pid = window.process_id self.whale_app = Application(backend="uia").connect(process=whale_pid) self.whale_window = self.whale_app.top_window() # 위치 및 크기 조절 self.hwnd_wrapper = HwndWrapper(self.whale_window.handle) self.hwnd_wrapper.move_window(x=1, y=1, width=1280, height=720) self.whale_window.set_focus() self.logger.info("웨일 창을 성공적으로 찾았습니다.") return self.whale_window self.logger.error("'새 시크릿 탭 - Whale' 창을 찾을 수 없습니다.") except Exception as e: self.logger.error(f"웨일 창 탐색 중 오류 발생: {e}", exc_info=True) return None def navigate_to_url(self, url): """주소창에 URL을 입력하고 페이지 로딩을 대기""" try: address_bar = self.whale_window.child_window(title="주소창 및 검색창", control_type="Edit") address_bar.click_input() address_bar.type_keys(f"{url}{{ENTER}}", with_spaces=True) logger.debug(f"{url}로 이동 중...") # 5초 동안 0.1초 간격으로 이미지 요소가 나타나는지 검사 start_time = time.time() while time.time() - start_time < 5: try: # 특정 이미지 요소를 찾으면 즉시 반환 image_element = self.whale_window.child_window(title="누락된 이미지 설명을 확인하려면 컨텍스트 메뉴를 여세요.", control_type="Image") if image_element.exists(timeout=0.5): logger.debug("페이지 로딩 완료: 이미지 요소가 나타났습니다.") return except Exception: pass # 요소가 아직 나타나지 않은 경우 대기 logger.debug("지정된 시간 내에 이미지 요소를 찾지 못했습니다.") except Exception as e: logger.error(f"주소창에 접근할 수 없습니다: {e}", exc_info=True) def check_translation_status(self, max_wait_time=10, check_interval=1): start_time = time.time() while time.time() - start_time < max_wait_time: try: fail_indicator = self.whale_window.child_window(title="번역할 영역을 선택하세요.", control_type="Text") if fail_indicator.exists(): logger.debug("번역 실패: '번역할 영역을 선택하세요.' 문구가 나타났습니다.") return "fail" image_element = self.whale_window.child_window(title="누락된 이미지 설명을 확인하려면 컨텍스트 메뉴를 여세요.", control_type="Image") if image_element.exists(): image_element.right_click_input() success_indicator = self.whale_window.child_window(title="이미지 복사(C)", control_type="MenuItem") if success_indicator.wait('visible', timeout=5): success_indicator.click_input() time.sleep(0.5) formats = clipboard.GetClipboardFormats() # logger.debug(f"클립보드에 있는 형식 목록: {formats}") for format_id in formats: format_name = clipboard.GetFormatName(format_id) # logger.debug(f"형식 ID {format_id}: {format_name}") if format_name in ("CF_BITMAP", "CF_DIB"): image_data = clipboard.GetData(format_id=format_id) if isinstance(image_data, bytes): logger.info("번역 성공: 클립보드에 이미지 데이터가 있습니다.") return "success" logger.info("번역이 아직 완료되지 않았습니다. 다시 시도 중...") except Exception as e: logger.error("클립보드 접근 중 오류 발생", exc_info=True) return "error" time.sleep(check_interval) logger.debug("번역 확인 시간 초과.") return "timeout" def right_click_on_image_and_inspect(self): try: image = self.whale_window.child_window(title="누락된 이미지 설명을 확인하려면 컨텍스트 메뉴를 여세요.", control_type="Image") if image.exists(): image.right_click_input() logger.debug("이미지 요소에서 우클릭을 수행했습니다.") else: logger.debug("이미지 요소를 찾을 수 없습니다.") return translate_menu_item = self.whale_window.child_window(title="이미지 번역 (R)", control_type="MenuItem") translate_menu_item.click_input() logger.debug("이미지 번역 명령이 실행되었습니다.") time.sleep(0.5) status = self.check_translation_status() if status == "success": logger.debug("번역이 성공적으로 완료되었습니다.") elif status == "fail": logger.debug("번역에 실패했습니다.") else: logger.debug("번역 상태를 확인할 수 없습니다.") except Exception as e: logger.debug(f"이미지 요소에서 우클릭 중 오류 발생: {e}", exc_info=True) def get_image_dimensions(self): """창 제목에서 이미지의 너비와 높이를 추출하여 반환합니다.""" if self.whale_window: try: title = self.whale_window.window_text() match = re.search(r"\((\d+)×(\d+)\)", title) if match: width, height = int(match.group(1)), int(match.group(2)) logger.debug(f"이미지 크기: 너비={width}, 높이={height}") return width, height else: logger.debug("창 제목에서 이미지 크기를 찾을 수 없습니다.") return None, None except Exception as e: logger.error("이미지 크기 추출 중 오류 발생", exc_info=True) return None, None else: logger.debug("웨일 창이 활성화되지 않았습니다.") return None, None def click_back_button(self): """'뒤로' 버튼을 클릭합니다.""" try: # '뒤로' 버튼 찾기 back_button = self.whale_window.child_window(title="뒤로", control_type="Button") if back_button.exists(): back_button.click_input() self.logger.debug("'뒤로' 버튼을 클릭했습니다.") else: self.logger.warning("'뒤로' 버튼을 찾을 수 없습니다.") except Exception as e: self.logger.error(f"'뒤로' 버튼 클릭 중 오류 발생: {e}", exc_info=True) def close_whale_window(self): """웨일 창을 종료하는 메서드.""" try: if self.app: self.app.kill() logger.debug("웨일 창을 성공적으로 종료했습니다.") else: logger.debug("웨일 애플리케이션이 시작되지 않았습니다.") except Exception as e: logger.error("웨일 창을 종료하는 중 오류 발생", exc_info=True) if __name__ == "__main__": translator = WhaleTranslator() translator.start_whale_in_secret_mode() # translator.find_whale_window() if translator.whale_window: translator.navigate_to_url("https://file.percenty.co.kr/public/652bed8e865b1f32ea62bf1f/products/6728686e9acd5506735107f0/dd4e8b61-da3a-4213-a953-d878d91651c7.jpg") translator.right_click_on_image_and_inspect() width, height = translator.get_image_dimensions() print(f"width : {width}, height : {height}") translator.close_whale_window()