├── .github └── workflows │ └── auto_renew.yml ├── README.md ├── auto_renew.py ├── last_renew_data.txt └── requirements.txt /.github/workflows/auto_renew.yml: -------------------------------------------------------------------------------- 1 | name: Auto Renew Tickhosting 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 */4 * *' # 每4天运行一次(96小时),在UTC时间00:00运行 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | Auto_renew_tickhosting: 13 | runs-on: windows-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Pull latest changes 22 | run: | 23 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 24 | git config --local user.name "github-actions[bot]" 25 | git pull --rebase origin main 26 | 27 | - name: Set up Python 28 | uses: actions/setup-python@v2 29 | with: 30 | python-version: '3.x' 31 | 32 | - name: Install Chrome 33 | uses: browser-actions/setup-chrome@latest 34 | 35 | - name: Install Python dependencies 36 | run: | 37 | python -m pip install --upgrade pip 38 | pip install -r requirements.txt 39 | 40 | - name: Run auto renew script 41 | env: 42 | EMAIL: ${{ secrets.EMAIL }} 43 | PASSWORD: ${{ secrets.PASSWORD }} 44 | PTERODACTYL_SESSION: ${{ secrets.PTERODACTYL_SESSION }} 45 | TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} 46 | TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} 47 | run: python auto_renew.py 48 | 49 | - name: Commit and push if changed 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | run: | 53 | git checkout main 54 | git add last_renew_data.txt 55 | git diff --cached --exit-code || git commit -m "Auto Update by Github Actions" 56 | git pull --rebase origin main || true 57 | git push origin main 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auto Renew Tickhosting 2 | 3 | 自动续期 TickHosting 免费游戏机的脚本,使用 GitHub Actions 每96小时自动运行一次。 4 | ## 部署 5 | - 部署文件:https://github.com/eooce/all-games/blob/main/java.tar.gz 6 | - 将files里的原server.jar文件改名为LICENSE.jar,将eula.txt改名为eula.txt1,再上传此压缩包解压得到server.jar和start.sh文件 7 | - server.jar的权限为444,start.sh的权限为777,此时还无法启动,会报错不支持的jar文件 8 | - 点开左侧的schedules菜单---右上角的Create schedule,随便给个名字创建,中间的Only When Server Is Online选项关闭,然后点击创建好的任务进入 9 | - 点击右上角的New Task,Action选项选择Send power action,打开Continue on Failure开关,点击Create Task创建 10 | - 点击Run now运行,返回左侧菜单栏中的terminal,显示提示已经开始下载文件点击进入files,将eula.txt1改回eula.txt 11 | - 返回左侧菜单栏中的terminal,查看运行完后是否运行游戏,运行中的弹窗需点击Accept 12 | - 完成 13 | 14 | ## 功能特点 15 | 16 | - 自动登录 TickHosting 17 | - 自动点击续期按钮 18 | - 验证续期是否成功 19 | - 每96小时自动运行 20 | - telegram消息推送 21 | - 支持手动触发运行 22 | 23 | ## 使用方法 24 | 25 | ### 1. 使用邮箱密码注册 并获取 Cookie 26 | 27 | 1. 打开 [TickHosting](https://tickhosting.com/auth/login),使用邮箱密码注册账号 28 | 2. 打开浏览器开发者工具(F12) 29 | 3. 切换到 Appcation 选项 30 | 4. 刷新页面 31 | 5. 在请求中找到 `pterodactyl_session` cookie 的值 32 | 33 | ### 2. 设置 GitHub Actions 34 | 35 | 1. Fork 这个仓库 36 | 2. 在仓库中设置 Secret: 37 | - 进入仓库的 Settings 38 | - 点击 Secrets and variables -> Actions 39 | - 点击 New repository secret 40 | - 添加```EMAIL```和```PASSWORD```环境便量 41 | - 添加`PTERODACTYL_SESSION`环境便量 42 | - Value: 您获取到的 pterodactyl_session cookie 值 43 | - ![PixPin_2024-12-18_12-40-50](https://github.com/user-attachments/assets/3ce6fa9e-611e-4810-a0ca-f35ddbe91400) 44 | - ![image](https://github.com/user-attachments/assets/97aa8e73-ba70-42ee-8882-ce3d3161894f) 45 | 46 | 3. telegram消息推送功能可选,如需要请在secrets中添加```TELEGRAM_BOT_TOKEN```和```TELEGRAM_CHAT_ID```环境变量 47 | 48 | ### 3. 验证运行 49 | 50 | - Actions 将每96小时(4天)自动运行一次 51 | - 您可以在 Actions 页面查看运行状态和日志 52 | - 需要立即运行时,可以在 Actions 页面手动触发 53 | 54 | ## 注意事项 55 | 56 | - 请确保 cookie及邮箱密码正确 57 | - 建议定期检查 Actions 运行日志,确保脚本正常运行 58 | - 如果需要修改运行频率,可以调整 `.github/workflows/auto_renew.yml` 中的 cron 表达式 59 | -------------------------------------------------------------------------------- /auto_renew.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.common.by import By 3 | from selenium.webdriver.support.ui import WebDriverWait 4 | from selenium.webdriver.support import expected_conditions as EC 5 | from selenium.common.exceptions import TimeoutException, NoSuchElementException 6 | from datetime import datetime 7 | import time 8 | from dateutil import parser 9 | import os 10 | import requests 11 | import re 12 | 13 | # 从环境变量读取登录凭据,默认使用PTERODACTYL_SESSION,账号密码作为备用方案,请在settings-actons里设置环境变量 14 | EMAIL = os.getenv('EMAIL', '') # 登录邮箱 15 | PASSWORD = os.getenv('PASSWORD', '') # 登录密码 16 | SESSION_COOKIE = os.getenv('PTERODACTYL_SESSION', '') 17 | 18 | # Telegram Bot 通知配置(可选) 19 | TELEGRAM_BOT_TOKEN = os.getenv('TELEGRAM_BOT_TOKEN', '') 20 | TELEGRAM_CHAT_ID = os.getenv('TELEGRAM_CHAT_ID', '') 21 | 22 | def setup_driver(): 23 | options = webdriver.ChromeOptions() 24 | options.add_argument('--headless') 25 | options.add_argument('--no-sandbox') 26 | options.add_argument('--disable-dev-shm-usage') 27 | options.add_argument('--disable-gpu') 28 | options.add_argument('--window-size=1920,1080') 29 | options.add_argument('--start-maximized') 30 | options.add_argument('--enable-logging') 31 | options.add_argument('--v=1') 32 | options.add_argument('--disable-blink-features=AutomationControlled') 33 | options.add_argument('--disable-extensions') 34 | return webdriver.Chrome(options=options) 35 | 36 | def add_cookies(driver): 37 | print("Current cookies before adding:", driver.get_cookies()) 38 | driver.delete_all_cookies() 39 | cookies = [ 40 | { 41 | 'name': 'PTERODACTYL_SESSION', 42 | 'value': os.environ['PTERODACTYL_SESSION'], 43 | 'domain': '.tickhosting.com' 44 | }, 45 | { 46 | 'name': 'pterodactyl_session', 47 | 'value': os.environ['PTERODACTYL_SESSION'], 48 | 'domain': '.tickhosting.com' 49 | } 50 | ] 51 | for cookie in cookies: 52 | try: 53 | driver.add_cookie(cookie) 54 | print(f"Added cookie: {cookie['name']}") 55 | except Exception as e: 56 | print(f"Error adding cookie {cookie['name']}: {str(e)}") 57 | 58 | print("Current cookies after adding:", driver.get_cookies()) 59 | 60 | def login_to_dashboard(driver): 61 | # try cookie login frist 62 | try: 63 | print("Attempting to login with cookies...") 64 | driver.get("https://tickhosting.com/") 65 | time.sleep(5) 66 | 67 | print("Adding cookies...") 68 | add_cookies(driver) 69 | 70 | print("Refreshing page after adding cookies...") 71 | driver.refresh() 72 | time.sleep(5) 73 | 74 | dashboard_urls = [ 75 | 'https://tickhosting.com' 76 | ] 77 | 78 | for url in dashboard_urls: 79 | try: 80 | print(f"Attempting to navigate to: {url}") 81 | driver.get(url) 82 | time.sleep(5) 83 | 84 | print(f"Current URL after navigation: {driver.current_url}") 85 | print(f"Current page title: {driver.title}") 86 | 87 | if driver.current_url.startswith('https://tickhosting.com') and 'Dashboard' in driver.title: 88 | print("Cookie login successful!") 89 | return True 90 | except Exception as e: 91 | print(f"Failed to navigate to {url}: {e}") 92 | 93 | print("Cookie login failed to reach dashboard.") 94 | except Exception as e: 95 | print(f"Cookie login error: {str(e)}") 96 | 97 | # if cookie login fails, try email and password 98 | try: 99 | if not EMAIL or not PASSWORD: 100 | raise ValueError("Email or password not set in environment variables") 101 | 102 | print("Attempting to login with email and password...") 103 | driver.get('https://tickhosting.com/auth/login') 104 | 105 | # wait for the login page to load 106 | time.sleep(8) 107 | 108 | # try different email and password input selectors 109 | email_selectors = [ 110 | (By.NAME, 'username'), 111 | (By.ID, 'email'), 112 | (By.NAME, 'email'), 113 | (By.XPATH, "//input[@type='email']"), 114 | ] 115 | 116 | password_selectors = [ 117 | (By.NAME, 'password'), 118 | (By.ID, 'password'), 119 | (By.XPATH, "//input[@type='password']"), 120 | ] 121 | 122 | login_button_selectors = [ 123 | (By.XPATH, "//button[@type='submit']"), 124 | (By.XPATH, "//button[contains(text(), 'Login')]"), 125 | ] 126 | 127 | # find the email and password input fields 128 | email_input = None 129 | for selector in email_selectors: 130 | try: 131 | email_input = driver.find_element(*selector) 132 | print(f"Found email input with selector: {selector}") 133 | break 134 | except Exception as e: 135 | print(f"Failed to find email input with selector {selector}: {e}") 136 | 137 | if not email_input: 138 | raise Exception("Could not find email input field") 139 | 140 | password_input = None 141 | for selector in password_selectors: 142 | try: 143 | password_input = driver.find_element(*selector) 144 | print(f"Found password input with selector: {selector}") 145 | break 146 | except Exception as e: 147 | print(f"Failed to find password input with selector {selector}: {e}") 148 | 149 | if not password_input: 150 | raise Exception("Could not find password input field") 151 | 152 | login_button = None 153 | for selector in login_button_selectors: 154 | try: 155 | login_button = driver.find_element(*selector) 156 | print(f"Found login button with selector: {selector}") 157 | break 158 | except Exception as e: 159 | print(f"Failed to find login button with selector {selector}: {e}") 160 | 161 | if not login_button: 162 | raise Exception("Could not find login button") 163 | 164 | email_input.clear() 165 | email_input.send_keys(EMAIL) 166 | password_input.clear() 167 | password_input.send_keys(PASSWORD) 168 | 169 | login_button.click() 170 | 171 | time.sleep(10) 172 | 173 | dashboard_urls = [ 174 | 'https://tickhosting.com' 175 | ] 176 | 177 | for url in dashboard_urls: 178 | try: 179 | print(f"Attempting to navigate to: {url}") 180 | driver.get(url) 181 | time.sleep(5) 182 | 183 | print(f"Current URL after email login: {driver.current_url}") 184 | print(f"Current page title: {driver.title}") 185 | 186 | if driver.current_url.startswith('https://tickhosting.com') and 'Dashboard' in driver.title: 187 | print("Email/password login successful!") 188 | return True 189 | except Exception as e: 190 | print(f"Failed to navigate to {url}: {e}") 191 | 192 | raise Exception("Login did not reach dashboard") 193 | 194 | except Exception as e: 195 | print(f"Login failed: {str(e)}") 196 | # 发送 Telegram 通知 197 | send_telegram_message(f"Auto Renew Login Error: {str(e)}") 198 | return False 199 | 200 | def try_login(driver): 201 | try: 202 | print("\nAttempting to navigate to dashboard...") 203 | driver.get("https://tickhosting.com") 204 | time.sleep(5) 205 | print(f"URL after navigation: {driver.current_url}") 206 | 207 | # Check if we're on the dashboard 208 | if driver.title == "Dashboard": 209 | print("Successfully reached dashboard") 210 | return True 211 | 212 | print("\nPage title:", driver.title) 213 | print("\nPage source preview:") 214 | print(driver.page_source[:2000]) 215 | return False 216 | 217 | except Exception as e: 218 | print(f"Error during login attempt: {str(e)}") 219 | return False 220 | 221 | def login_with_credentials(driver): 222 | try: 223 | # get the login page 224 | driver.get('https://tickhosting.com/auth/login') 225 | 226 | # wait for the login page to load 227 | WebDriverWait(driver, 10).until( 228 | EC.presence_of_element_located((By.NAME, 'email')) 229 | ) 230 | 231 | # Locate the mailbox and password input box 232 | email_input = driver.find_element(By.NAME, 'email') 233 | password_input = driver.find_element(By.NAME, 'password') 234 | 235 | email_input.clear() 236 | email_input.send_keys(EMAIL) 237 | password_input.clear() 238 | password_input.send_keys(PASSWORD) 239 | 240 | # Locate and click the login button 241 | login_button = driver.find_element(By.XPATH, "//button[contains(text(), 'Login') or contains(text(), '登录')]") 242 | login_button.click() 243 | 244 | # wait for login to complete 245 | WebDriverWait(driver, 10).until( 246 | EC.url_contains('dashboard') 247 | ) 248 | 249 | print("Login successful!") 250 | return True 251 | 252 | except Exception as e: 253 | print(f"Login failed: {str(e)}") 254 | return False 255 | 256 | def wait_and_find_element(driver, by, value, timeout=20, description=""): 257 | try: 258 | print(f"Waiting for element: {description} ({value})") 259 | element = WebDriverWait(driver, timeout).until( 260 | EC.presence_of_element_located((by, value)) 261 | ) 262 | time.sleep(2) 263 | print(f"Found element: {description}") 264 | return element 265 | except Exception as e: 266 | print(f"Failed to find element: {description}") 267 | print(f"Error: {str(e)}") 268 | print(f"Current URL: {driver.current_url}") 269 | print(f"Page source: {driver.page_source[:1000]}...") 270 | driver.save_screenshot(f'debug_{description.lower().replace(" ", "_")}.png') 271 | raise 272 | 273 | def send_telegram_message(message): 274 | if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID: 275 | print("Telegram bot token or chat ID not configured. Skipping Telegram notification.") 276 | return False 277 | 278 | url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage" 279 | 280 | payload = { 281 | "chat_id": TELEGRAM_CHAT_ID, 282 | "text": message 283 | } 284 | 285 | try: 286 | response = requests.post(url, json=payload) 287 | response.raise_for_status() 288 | print("Telegram notification sent successfully.") 289 | return True 290 | except Exception as e: 291 | print(f"Failed to send Telegram notification: {e}") 292 | return False 293 | 294 | def update_last_renew_time(success, new_time=None, error_message=None, server_id=None): 295 | current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 296 | 297 | status = "Success" if success else "Failed" 298 | 299 | content = f"Server ID: {server_id or 'Unknown'}\n" 300 | content += f"Renew status: {status}\n" 301 | content += f"Last renewal time: {current_time}\n" 302 | 303 | # if rennew successfuul,add new expiration time 304 | if success and new_time: 305 | content += f"New expiration time: {new_time}" 306 | elif not success and error_message: 307 | content += f"Error: {error_message}" 308 | 309 | with open('last_renew_data.txt', 'w', encoding='utf-8') as f: 310 | f.write(content) 311 | 312 | # send Telegram notification 313 | telegram_message = f"**Tickhosting Server Renewal Notification**\n{content}" 314 | send_telegram_message(telegram_message) 315 | 316 | def get_expiration_time(driver): 317 | try: 318 | elements = driver.find_elements(By.CSS_SELECTOR, ".RenewBox___StyledP-sc-1inh2rq-4") 319 | 320 | if elements: 321 | expiry_text = elements[0].text 322 | print(f"Found expiration time: {expiry_text}") 323 | 324 | if expiry_text.startswith("EXPIRED: "): 325 | expiry_text = expiry_text.replace("EXPIRED: ", "").strip() 326 | 327 | return expiry_text 328 | else: 329 | print("No expiration time elements found") 330 | return None 331 | 332 | except Exception as e: 333 | print(f"Error finding expiration time: {e}") 334 | return None 335 | 336 | def main(): 337 | driver = None 338 | try: 339 | print("Starting browser...") 340 | driver = setup_driver() 341 | driver.set_page_load_timeout(30) 342 | 343 | print("Navigating to website...") 344 | driver.get("https://tickhosting.com") 345 | time.sleep(5) 346 | 347 | # try login to dashboard 348 | if not login_to_dashboard(driver): 349 | raise Exception("Unable to login to dashboard") 350 | 351 | print("Refreshing page after login...") 352 | driver.refresh() 353 | time.sleep(5) # Give more time for the page to load 354 | 355 | print(f"Current URL after refresh: {driver.current_url}") 356 | print("Taking screenshot of current page state...") 357 | driver.save_screenshot('debug_after_refresh.png') 358 | 359 | if not try_login(driver): 360 | raise Exception("Failed to reach dashboard") 361 | 362 | print("\nLooking for server elements...") 363 | selectors = [ 364 | ("xpath", "//div[contains(@class, 'status-bar')]"), 365 | ("xpath", "//div[contains(@class, 'server-status')]"), 366 | ("xpath", "//div[contains(@class, 'server-card')]"), 367 | ("css", ".status-bar"), 368 | ("css", ".server-card") 369 | ] 370 | 371 | # Wait for page to fully load 372 | print("Waiting for page to fully load...") 373 | time.sleep(10) 374 | 375 | print("Taking screenshot before looking for status elements...") 376 | driver.save_screenshot('debug_before_status.png') 377 | 378 | print("Current page title:", driver.title) 379 | print("Current URL:", driver.current_url) 380 | 381 | server_element = None 382 | for selector_type, selector in selectors: 383 | try: 384 | print(f"Trying {selector_type} selector: {selector}") 385 | if selector_type == "xpath": 386 | elements = driver.find_elements(By.XPATH, selector) 387 | else: 388 | elements = driver.find_elements(By.CSS_SELECTOR, selector) 389 | 390 | if elements: 391 | print(f"Found {len(elements)} elements with {selector_type} selector: {selector}") 392 | for element in elements: 393 | try: 394 | print(f"Element text: {element.text}") 395 | print(f"Element HTML: {element.get_attribute('outerHTML')}") 396 | except: 397 | pass 398 | server_element = elements[0] 399 | break 400 | except Exception as e: 401 | print(f"Failed with {selector_type} selector {selector}: {str(e)}") 402 | continue 403 | 404 | if not server_element: 405 | raise Exception("Could not find server element with any selector") 406 | 407 | print("Clicking server element...") 408 | driver.execute_script("arguments[0].click();", server_element) 409 | 410 | # Wait for server page to load completely 411 | print("Waiting for server page to load completely...") 412 | WebDriverWait(driver, 10).until( 413 | EC.presence_of_element_located((By.TAG_NAME, "body")) 414 | ) 415 | 416 | # Print current URL immediately after page load 417 | print(f"Server page URL after load: {driver.current_url}") 418 | 419 | # Print page title for additional verification 420 | print(f"Server page title: {driver.title}") 421 | 422 | print("Taking screenshot of server page...") 423 | driver.save_screenshot('debug_server_page.png') 424 | 425 | # Additional logging to ensure URL is captured 426 | print(f"Confirmed server page URL: {driver.current_url}") 427 | 428 | # Print full page source 429 | print("\nFull Page Source (first 10000 characters):") 430 | print(driver.page_source[:10000]) 431 | 432 | # print button elements 433 | all_buttons = driver.find_elements(By.TAG_NAME, "button") 434 | print(f"\nTotal buttons found: {len(all_buttons)}") 435 | for idx, button in enumerate(all_buttons, 1): 436 | try: 437 | print(f"Button {idx}:") 438 | print(f" Text: '{button.text}'") 439 | print(f" Visible: {button.is_displayed()}") 440 | print(f" Enabled: {button.is_enabled()}") 441 | print(f" Class: '{button.get_attribute('class')}'") 442 | print(f" Outer HTML: '{button.get_attribute('outerHTML')}'") 443 | print("---") 444 | except Exception as e: 445 | print(f"Error processing button {idx}: {e}") 446 | 447 | # print span elements 448 | all_spans = driver.find_elements(By.TAG_NAME, "span") 449 | print(f"\nTotal spans found: {len(all_spans)}") 450 | for idx, span in enumerate(all_spans, 1): 451 | try: 452 | print(f"Span {idx}:") 453 | print(f" Text: '{span.text}'") 454 | print(f" Class: '{span.get_attribute('class')}'") 455 | print(f" Outer HTML: '{span.get_attribute('outerHTML')}'") 456 | print("---") 457 | except Exception as e: 458 | print(f"Error processing span {idx}: {e}") 459 | 460 | # get server ID 461 | try: 462 | current_url = driver.current_url 463 | print(f"\nCurrent URL: {current_url}") 464 | 465 | server_id_match = re.search(r'/server/([a-f0-9]+)', current_url) 466 | server_id = server_id_match.group(1) if server_id_match else 'Unknown' 467 | 468 | print(f"Extracted Server ID: {server_id}") 469 | except Exception as e: 470 | print(f"Error extracting server ID: {e}") 471 | server_id = 'Unknown' 472 | 473 | renew_selectors = [ 474 | ("xpath", "//span[contains(@class, 'Button___StyledSpan-sc-1qu1gou-2')]/parent::button"), 475 | ("css", "button.Button__ButtonStyle-sc-1qu1gou-0.beoWBB.RenewBox___StyledButton-sc-1inh2rq-7.hMqrbU"), 476 | ("xpath", "//button[contains(@class, 'Button__ButtonStyle-sc-1qu1gou-0') and contains(@class, 'RenewBox___StyledButton')]"), 477 | ("xpath", "//button[.//span[text()='ADD 96 HOUR(S)']]"), 478 | ("xpath", "//button[.//span[contains(text(), 'ADD 96 HOUR')]]"), 479 | ("xpath", "//button[@color='primary' and contains(@class, 'Button__ButtonStyle')]") 480 | ] 481 | 482 | print("\nWaiting for any button to become visible...") 483 | try: 484 | WebDriverWait(driver, 10).until( 485 | EC.presence_of_element_located((By.TAG_NAME, "button")) 486 | ) 487 | print("Found at least one button on the page") 488 | except TimeoutException: 489 | print("No buttons found after waiting") 490 | 491 | renew_button = None 492 | for selector_type, selector in renew_selectors: 493 | try: 494 | print(f"Looking for renew button with {selector_type}: {selector}") 495 | if selector_type == "xpath": 496 | elements = driver.find_elements(By.XPATH, selector) 497 | else: 498 | elements = driver.find_elements(By.CSS_SELECTOR, selector) 499 | 500 | if elements: 501 | print(f"Found {len(elements)} elements with {selector_type}: {selector}") 502 | for element in elements: 503 | print(f"Element text: {element.text}") 504 | print(f"Element HTML: {element.get_attribute('outerHTML')}") 505 | renew_button = elements[0] 506 | break 507 | except Exception as e: 508 | print(f"Failed with {selector_type} selector {selector}: {str(e)}") 509 | continue 510 | 511 | if not renew_button: 512 | raise Exception("Could not find renew button") 513 | 514 | # Get initial expiration time 515 | initial_time = get_expiration_time(driver) 516 | 517 | # Click renew button 518 | renew_button.click() 519 | 520 | # Wait for page to update 521 | time.sleep(70) # Increased wait time 522 | driver.refresh() 523 | time.sleep(8) # Additional wait after refresh 524 | 525 | new_expiration_time = get_expiration_time(driver) 526 | 527 | if initial_time and new_expiration_time: 528 | try: 529 | initial_datetime = parser.parse(initial_time) 530 | new_datetime = parser.parse(new_expiration_time) 531 | 532 | if new_datetime > initial_datetime: 533 | print("Renewal successful! Time has been extended.") 534 | print(f"Initial time: {initial_time}") 535 | print(f"New time: {new_expiration_time}") 536 | update_last_renew_time( 537 | success=True, 538 | new_time=new_expiration_time, 539 | server_id=server_id 540 | ) 541 | else: 542 | print("Renewal may have failed. Time was not extended.") 543 | update_last_renew_time( 544 | success=False, 545 | error_message="Time not extended", 546 | server_id=server_id 547 | ) 548 | except Exception as e: 549 | print(f"Error parsing dates: {str(e)}") 550 | update_last_renew_time( 551 | success=False, 552 | error_message=f"Date parsing error: {str(e)}", 553 | server_id=server_id 554 | ) 555 | else: 556 | print("Could not verify renewal - unable to get expiration times") 557 | update_last_renew_time( 558 | success=False, 559 | error_message="Could not find expiration times", 560 | server_id=server_id 561 | ) 562 | 563 | except TimeoutException as e: 564 | error_msg = f"Timeout error: {str(e)}" 565 | print(error_msg) 566 | if driver: 567 | print(f"Current URL: {driver.current_url}") 568 | driver.save_screenshot('error_timeout.png') 569 | update_last_renew_time(False, error_message=error_msg) 570 | except Exception as e: 571 | error_msg = f"An error occurred: {str(e)}" 572 | print(error_msg) 573 | if driver: 574 | print(f"Current URL: {driver.current_url}") 575 | driver.save_screenshot('error_general.png') 576 | update_last_renew_time(False, error_message=error_msg) 577 | finally: 578 | if driver: 579 | try: 580 | driver.quit() 581 | except Exception as e: 582 | print(f"Error closing browser: {str(e)}") 583 | 584 | if __name__ == "__main__": 585 | main() 586 | -------------------------------------------------------------------------------- /last_renew_data.txt: -------------------------------------------------------------------------------- 1 | Server ID: Unknown 2 | Renew status: Failed 3 | Last renewal time: 2025-01-13 01:00:26 4 | Error: An error occurred: Unable to login to dashboard -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium==4.16.0 2 | webdriver_manager==4.0.1 3 | python-dateutil==2.8.2 4 | --------------------------------------------------------------------------------