LTTEAM commited on
Commit
d2ea8a4
·
verified ·
1 Parent(s): 054b780

Create runner.py

Browse files
Files changed (1) hide show
  1. runner.py +237 -0
runner.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys, os, json, time, threading, re
2
+ import undetected_chromedriver as uc
3
+ from selenium.webdriver.common.by import By
4
+ from selenium.webdriver.common.keys import Keys
5
+ from selenium.webdriver.common.action_chains import ActionChains
6
+ from selenium.webdriver.support.ui import WebDriverWait
7
+ from selenium.webdriver.support import expected_conditions as EC
8
+ from selenium.common.exceptions import TimeoutException
9
+
10
+ # Cấu hình chung
11
+ CURRENT_VERSION = "1.0.3"
12
+ UPDATE_CHECK_URL = "https://drive.google.com/uc?export=download&id=1hkRegTsVohMNxM7o33Jj3FRix0GyEhUW"
13
+ TARGET_URL = "https://hailuoai.video/create"
14
+ COOKIES_FILE = "cookies.json"
15
+ IMAGE_FOLDER = "images"
16
+ INPUT_TEXT_FILE = "input.txt"
17
+ DOWNLOAD_TIMEOUT = 60 # giây
18
+
19
+ def normalize_text(text):
20
+ replacements = {
21
+ "‘": "'", "’": "'", "“": '"', "”": '"', "…": "..."
22
+ }
23
+ for old, new in replacements.items():
24
+ text = text.replace(old, new)
25
+ return re.sub(r'\s+', ' ', text).strip().lower()
26
+
27
+ class AutomationRunner:
28
+ def __init__(self, headless, wait_time, avatar_image_path=None, video_folder="outputs", mode="subject", log_callback=None):
29
+ self.headless = headless
30
+ self.wait_time = wait_time
31
+ self.avatar_image_path = avatar_image_path
32
+ self.video_folder = video_folder
33
+ self.mode = mode
34
+ self.log = log_callback or (lambda msg: None)
35
+
36
+ def setup_driver(self):
37
+ self.log("🔧 Khởi tạo trình duyệt...")
38
+ options = uc.ChromeOptions()
39
+ if self.headless:
40
+ options.add_argument('--headless=new')
41
+ options.add_argument('--window-size=1920,1080')
42
+ os.makedirs(self.video_folder, exist_ok=True)
43
+ prefs = {
44
+ "download.default_directory": os.path.abspath(self.video_folder),
45
+ "download.prompt_for_download": False,
46
+ "download.directory_upgrade": True,
47
+ }
48
+ options.add_experimental_option("prefs", prefs)
49
+ driver = uc.Chrome(options=options)
50
+ if not self.headless:
51
+ driver.maximize_window()
52
+ time.sleep(2)
53
+ return driver
54
+
55
+ def save_cookies(self, driver):
56
+ with open(COOKIES_FILE, 'w', encoding='utf-8') as f:
57
+ json.dump(driver.get_cookies(), f, ensure_ascii=False, indent=2)
58
+ self.log(f"✅ Lưu cookies vào {COOKIES_FILE}")
59
+
60
+ def load_cookies(self, driver):
61
+ try:
62
+ cookies = json.load(open(COOKIES_FILE, 'r', encoding='utf-8'))
63
+ for c in cookies:
64
+ # adjust SameSite
65
+ if c.get('sameSite') == 'None':
66
+ c['sameSite'] = 'Strict'
67
+ try:
68
+ driver.add_cookie(c)
69
+ except Exception:
70
+ pass
71
+ self.log("✅ Nạp cookies thành công")
72
+ except FileNotFoundError:
73
+ self.log("⚠️ Chưa có file cookies.json, sẽ login thủ công")
74
+
75
+ def click_tab(self, driver, xpath, success_msg, fail_msg):
76
+ try:
77
+ el = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, xpath)))
78
+ el.click()
79
+ self.log(success_msg)
80
+ except Exception as e:
81
+ self.log(f"{fail_msg}: {e}")
82
+
83
+ def click_confirm(self, driver):
84
+ self.click_tab(
85
+ driver,
86
+ "//*[contains(text(),'Confirm')]",
87
+ "✅ Nhấn Confirm",
88
+ "❌ Không tìm thấy Confirm"
89
+ )
90
+
91
+ def upload_images_silently(self, driver):
92
+ try:
93
+ btn = WebDriverWait(driver, 10).until(
94
+ EC.element_to_be_clickable((
95
+ By.XPATH,
96
+ "//div[contains(text(),'Add reference character') and contains(@class,'hover:text-white')]"
97
+ ))
98
+ )
99
+ btn.click()
100
+ time.sleep(2)
101
+ inp = driver.find_element(By.XPATH, "//input[@type='file']")
102
+ driver.execute_script("arguments[0].style.display='block';", inp)
103
+ paths = []
104
+ if self.avatar_image_path:
105
+ paths = [os.path.abspath(self.avatar_image_path)]
106
+ else:
107
+ imgs = [f for f in os.listdir(IMAGE_FOLDER) if f.lower().endswith((".png",".jpg",".jpeg"))]
108
+ paths = [os.path.abspath(os.path.join(IMAGE_FOLDER,f)) for f in imgs]
109
+ inp.send_keys("\n".join(paths))
110
+ time.sleep(1)
111
+ self.click_confirm(driver) # modal upload
112
+ self.log(f"✅ Upload ảnh: {paths}")
113
+ except Exception as e:
114
+ self.log(f"⚠️ Upload ảnh thất bại: {e}")
115
+
116
+ def load_scenes(self):
117
+ out = []
118
+ with open(INPUT_TEXT_FILE, 'r', encoding='utf-8') as f:
119
+ for line in f:
120
+ line=line.strip()
121
+ if not line: continue
122
+ content = line.split(":",1)[1].strip() if ":" in line else line
123
+ out.append(normalize_text(content))
124
+ return out
125
+
126
+ def process_prompts(self, driver, prompts):
127
+ sent = []
128
+ for p in prompts:
129
+ if p in sent:
130
+ self.log(f"ℹ️ Bỏ qua prompt đã gửi: {p}")
131
+ continue
132
+ # nhập prompt
133
+ tb = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "video-create-textarea")))
134
+ tb.click(); tb.send_keys(Keys.CONTROL, "a", Keys.BACKSPACE)
135
+ tb.send_keys(p, Keys.ENTER)
136
+ self.log(f"✍️ Nhập prompt: {p}")
137
+ # click Create
138
+ btn = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((
139
+ By.XPATH,
140
+ "//button[.//img[@alt='AI Video create png by Hailuo AI Video Generator']]"
141
+ )))
142
+ btn.click()
143
+ self.log("▶️ Click Create")
144
+ # kiểm tra queue
145
+ try:
146
+ que = WebDriverWait(driver, 10).until(
147
+ EC.visibility_of_element_located((By.CSS_SELECTOR,"div.adm-auto-center-content"))
148
+ )
149
+ if "full" in que.text.lower():
150
+ self.log("⏳ Queue đầy, sẽ thử lại sau 3s")
151
+ time.sleep(3)
152
+ continue
153
+ except TimeoutException:
154
+ pass
155
+ sent.append(p)
156
+ self.log(f"✅ Prompt chấp nhận: {p}")
157
+ return sent
158
+
159
+ def download_all(self, driver, prompts):
160
+ # đơn giản: load mine page, scroll, download
161
+ driver.get("https://hailuoai.video/mine")
162
+ time.sleep(5)
163
+ files_before = set(os.listdir(self.video_folder))
164
+ for _ in range(3):
165
+ driver.execute_script("window.scrollTo(0,document.body.scrollHeight);")
166
+ time.sleep(2)
167
+ items = driver.find_elements(By.XPATH,"//div[contains(@class,'mine-video-item')]")
168
+ for it in items:
169
+ try:
170
+ ActionChains(driver).move_to_element(it).perform()
171
+ p = normalize_text(it.find_element(By.CSS_SELECTOR,".prompt-plain-span").text)
172
+ if p in prompts:
173
+ btns = it.find_elements(By.TAG_NAME,"button")
174
+ for b in btns:
175
+ if "Download" in b.text or b.get_attribute("innerHTML").lower().find("recreate")<0:
176
+ b.click()
177
+ self.log(f"⬇️ Download prompt: {p}")
178
+ break
179
+ except:
180
+ pass
181
+ # chờ download
182
+ t0 = time.time()
183
+ while time.time()-t0 < self.wait_time:
184
+ if any(f.endswith(".crdownload") for f in os.listdir(self.video_folder)):
185
+ time.sleep(1)
186
+ else:
187
+ break
188
+ # đổi tên theo thứ tự
189
+ for idx,p in enumerate(prompts,1):
190
+ matches = [f for f in os.listdir(self.video_folder) if f.endswith(".mp4")]
191
+ if matches:
192
+ src = max(matches, key=lambda f:os.path.getctime(os.path.join(self.video_folder,f)))
193
+ dst = os.path.join(self.video_folder, f"Prompt {idx}.mp4")
194
+ os.rename(os.path.join(self.video_folder,src), dst)
195
+ self.log(f"🔄 Đổi tên {src} → Prompt {idx}.mp4")
196
+
197
+ def run(self):
198
+ driver = self.setup_driver()
199
+ driver.get(TARGET_URL)
200
+ time.sleep(5)
201
+
202
+ # cookies / login
203
+ if os.path.exists(COOKIES_FILE):
204
+ self.load_cookies(driver)
205
+ driver.refresh()
206
+ time.sleep(5)
207
+ else:
208
+ self.log("❗ Vui lòng login thủ công để lưu cookies rồi deploy lại.")
209
+ driver.quit()
210
+ return
211
+
212
+ # chọn mode
213
+ if self.mode=="subject":
214
+ self.click_tab(driver,
215
+ "//*[contains(text(),'Subject Reference')]",
216
+ "✅ Chuyển Subject Reference",
217
+ "❌ Không tìm Subject Reference")
218
+ time.sleep(2)
219
+ self.click_confirm(driver); time.sleep(2)
220
+ self.upload_images_silently(driver)
221
+ else:
222
+ self.click_tab(driver,
223
+ "//div[span[text()='Text to Video']]",
224
+ "✅ Chuyển Text to Video",
225
+ "❌ Không tìm Text to Video")
226
+ time.sleep(2)
227
+ self.click_confirm(driver)
228
+
229
+ scenes = self.load_scenes()
230
+ self.log(f"📋 Prompts: {scenes}")
231
+ sent = self.process_prompts(driver, scenes)
232
+ self.log(f"⏳ Chờ {self.wait_time}s để xử lý video...")
233
+ time.sleep(self.wait_time)
234
+ self.download_all(driver, sent)
235
+
236
+ driver.quit()
237
+ self.log("🏁 Automation hoàn tất.")