mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-18 07:23:03 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 842fb434f4 | |||
| 6cabddf0cd | |||
| 0322558339 |
@@ -306,6 +306,9 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
|
||||
self.MaxEndTimeDiffSpinBox.setValue(30)
|
||||
self.ExpectDurationSpinBox.setValue(self.BeginTimeEdit.time().secsTo(self.EndTimeEdit.time())/3600)
|
||||
self.SatisfyDurationCheckBox.setChecked(False)
|
||||
self.ExpectRenewDurationSpinBox.setValue(1.0)
|
||||
self.MaxRenewTimeDiffSpinBox.setValue(30)
|
||||
self.PreferLateRenewTimeCheckBox.setChecked(False)
|
||||
|
||||
|
||||
def collectUserConfigFromUserInfoWidget(
|
||||
@@ -317,7 +320,8 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
|
||||
"password": self.PasswordEdit.text(),
|
||||
"reserve_info": {
|
||||
"begin_time":{},
|
||||
"end_time": {}
|
||||
"end_time": {},
|
||||
"renew_time": {}
|
||||
}
|
||||
}
|
||||
user_config["reserve_info"]["date"] = self.DateEdit.dateTime().toString("yyyy-MM-dd")
|
||||
@@ -333,6 +337,9 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
|
||||
user_config["reserve_info"]["end_time"]["prefer_early"] = not self.PreferLateEndTimeCheckBox.isChecked()
|
||||
user_config["reserve_info"]["expect_duration"] = self.ExpectDurationSpinBox.value()
|
||||
user_config["reserve_info"]["satisfy_duration"] = self.SatisfyDurationCheckBox.isChecked()
|
||||
user_config["reserve_info"]["renew_time"]["expect_duration"] = self.ExpectRenewDurationSpinBox.value()
|
||||
user_config["reserve_info"]["renew_time"]["max_diff"] = self.MaxRenewTimeDiffSpinBox.value()
|
||||
user_config["reserve_info"]["renew_time"]["prefer_early"] = not self.PreferLateRenewTimeCheckBox.isChecked()
|
||||
return user_config
|
||||
|
||||
|
||||
@@ -371,6 +378,9 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
|
||||
self.PreferLateEndTimeCheckBox.setChecked(not user_config["reserve_info"]["end_time"]["prefer_early"])
|
||||
self.ExpectDurationSpinBox.setValue(user_config["reserve_info"]["expect_duration"])
|
||||
self.SatisfyDurationCheckBox.setChecked(user_config["reserve_info"]["satisfy_duration"])
|
||||
self.ExpectRenewDurationSpinBox.setValue(user_config["reserve_info"]["renew_time"]["expect_duration"])
|
||||
self.MaxRenewTimeDiffSpinBox.setValue(user_config["reserve_info"]["renew_time"]["max_diff"])
|
||||
self.PreferLateRenewTimeCheckBox.setChecked(not user_config["reserve_info"]["renew_time"]["prefer_early"])
|
||||
except:
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
@@ -565,7 +575,12 @@ class ALConfigWidget(QWidget, Ui_ALConfigWidget):
|
||||
"prefer_early": True
|
||||
},
|
||||
"expect_duration": 2.0,
|
||||
"satisfy_duration": False
|
||||
"satisfy_duration": False,
|
||||
"renew_time": {
|
||||
"expect_duration": 1.0,
|
||||
"max_diff": 30,
|
||||
"prefer_early": True
|
||||
}
|
||||
}
|
||||
}
|
||||
user_item = QListWidgetItem(new_user["username"])
|
||||
|
||||
+539
-436
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@ from operators.LibLogin import LibLogin
|
||||
from operators.LibLogout import LibLogout
|
||||
from operators.LibReserve import LibReserve
|
||||
from operators.LibCheckin import LibCheckin
|
||||
from operators.LibRenew import LibRenew
|
||||
|
||||
from utils.ConfigReader import ConfigReader
|
||||
|
||||
@@ -114,6 +115,7 @@ class AutoLib(MsgBase):
|
||||
self.__lib_logout = LibLogout(self._input_queue, self._output_queue, self.__driver)
|
||||
self.__lib_reserve = LibReserve(self._input_queue, self._output_queue, self.__driver)
|
||||
self.__lib_checkin = LibCheckin(self._input_queue, self._output_queue, self.__driver)
|
||||
self.__lib_renew = LibRenew(self._input_queue, self._output_queue, self.__driver)
|
||||
|
||||
|
||||
def __waitResponseLoad(
|
||||
@@ -186,30 +188,29 @@ class AutoLib(MsgBase):
|
||||
if run_mode["auto_reserve"]:
|
||||
if self.__lib_checker.canReserve(reserve_info.get("date")):
|
||||
if self.__lib_reserve.reserve(reserve_info):
|
||||
self._showTrace(f"用户 {username} 预约成功 !")
|
||||
result = 0
|
||||
else:
|
||||
self._showTrace(f"用户 {username} 预约失败 !")
|
||||
result = 1
|
||||
else:
|
||||
self._showTrace(f"用户 {username} 无法预约,已跳过")
|
||||
result = 2
|
||||
# checkin
|
||||
if run_mode["auto_checkin"] and result == 2:
|
||||
if self.__lib_checker.canCheckin(reserve_info.get("date")):
|
||||
if self.__lib_checker.canCheckin():
|
||||
if self.__lib_checkin.checkin(username):
|
||||
self._showTrace(f"用户 {username} 签到成功 !")
|
||||
result = 0
|
||||
else:
|
||||
self._showTrace(f"用户 {username} 签到失败 !")
|
||||
result = 1
|
||||
else:
|
||||
self._showTrace(f"用户 {username} 无法签到,已跳过")
|
||||
result = 2
|
||||
# renewal
|
||||
if run_mode["auto_renewal"] and result == 2:
|
||||
if self.__lib_checker.canRenew(reserve_info.get("date")):
|
||||
pass
|
||||
if record := self.__lib_checker.canRenew():
|
||||
if self.__lib_renew.renew(username, record, reserve_info):
|
||||
result = 0
|
||||
else:
|
||||
result = 1
|
||||
else:
|
||||
self._showTrace(f"用户 {username} 无法续约,已跳过")
|
||||
result = 2
|
||||
|
||||
@@ -54,7 +54,6 @@ class LibCheckin(LibOperator):
|
||||
except:
|
||||
self._showTrace("签到时发生未知错误 !")
|
||||
return False
|
||||
print(result_message_element)
|
||||
result_message = result_message_element.text
|
||||
if "签到成功" in result_message:
|
||||
try:
|
||||
@@ -73,14 +72,16 @@ class LibCheckin(LibOperator):
|
||||
f" {details[3]}\n"\
|
||||
f" {details[4]}")
|
||||
else:
|
||||
self._showTrace(
|
||||
self._showTrace(f"\n"\
|
||||
" 签到成功 !\n"\
|
||||
" 未获取到签到详情 !")
|
||||
ok_btn.click()
|
||||
return True
|
||||
else:
|
||||
failure_reason = result_message.replace("签到失败", "").strip()
|
||||
self._showTrace(f"签到失败: {failure_reason}")
|
||||
self._showTrace(f"\n"\
|
||||
" 签到失败 !\n"\
|
||||
f" {failure_reason}")
|
||||
ok_btn.click()
|
||||
return False
|
||||
|
||||
@@ -104,4 +105,9 @@ class LibCheckin(LibOperator):
|
||||
self._showTrace("签到按钮不可用, 可能不在场馆内, 请连接图书馆网络后重试")
|
||||
return False
|
||||
checkin_btn.click()
|
||||
return self._waitResponseLoad()
|
||||
if self._waitResponseLoad():
|
||||
self._showTrace(f"用户 {username} 签到成功 !")
|
||||
return True
|
||||
else:
|
||||
self._showTrace(f"用户 {username} 签到失败 !")
|
||||
return False
|
||||
|
||||
+184
-1
@@ -37,4 +37,187 @@ class LibRenew(LibOperator):
|
||||
self
|
||||
) -> bool:
|
||||
|
||||
pass
|
||||
try:
|
||||
WebDriverWait(self.__driver, 2).until(
|
||||
EC.presence_of_element_located((By.CLASS_NAME, "ui_dialog"))
|
||||
)
|
||||
WebDriverWait(self.__driver, 2).until(
|
||||
EC.presence_of_element_located((By.CLASS_NAME, "resultMessage"))
|
||||
)
|
||||
WebDriverWait(self.__driver, 2).until(
|
||||
EC.element_to_be_clickable((By.CLASS_NAME, "btnOK"))
|
||||
)
|
||||
result_message_element = self.__driver.find_element(
|
||||
By.CLASS_NAME, "resultMessage"
|
||||
)
|
||||
ok_btn = self.__driver.find_element(By.CLASS_NAME, "btnOK")
|
||||
except:
|
||||
self._showTrace("续约时发生未知错误 !")
|
||||
return False
|
||||
result_message = result_message_element.text
|
||||
if "续约成功" in result_message:
|
||||
try:
|
||||
detail_elements = self.__driver.find_elements(
|
||||
By.CSS_SELECTOR, ".resultMessage dd"
|
||||
)
|
||||
except:
|
||||
pass
|
||||
if detail_elements:
|
||||
details = [element.text for element in detail_elements if element.text.strip()]
|
||||
if len(details) >= 5:
|
||||
self._showTrace(f"\n"\
|
||||
f" 续约成功 !\n"\
|
||||
f" {details[1]}\n"\
|
||||
f" {details[2]}\n"\
|
||||
f" {details[3]}\n"\
|
||||
f" {details[4]}")
|
||||
else:
|
||||
self._showTrace(f"\n"\
|
||||
" 续约成功 !\n"\
|
||||
" 未获取到续约详情 !")
|
||||
ok_btn.click()
|
||||
return True
|
||||
else:
|
||||
failure_reason = result_message.replace("续约失败", "").strip()
|
||||
self._showTrace(f"\n"\
|
||||
" 续约失败 !\n"\
|
||||
f" {failure_reason}"
|
||||
)
|
||||
ok_btn.click()
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def __timeToMins(
|
||||
time_str: str
|
||||
) -> int:
|
||||
|
||||
hour, minute = map(int, time_str.split(":"))
|
||||
return hour*60 + minute
|
||||
|
||||
|
||||
@staticmethod
|
||||
def __minsToTime(
|
||||
mins: int
|
||||
) -> str:
|
||||
|
||||
hour, minute = divmod(mins, 60)
|
||||
return f"{hour:02d}:{minute:02d}"
|
||||
|
||||
|
||||
def __selectNearstRecord(
|
||||
self,
|
||||
record: dict,
|
||||
reserve_info: dict
|
||||
) -> bool:
|
||||
|
||||
end_time = record["time"]["end"]
|
||||
renew_info = reserve_info["renew_time"]
|
||||
max_diff = renew_info["max_diff"]
|
||||
prefer_earlier = renew_info["prefer_early"]
|
||||
target_renew_mins = self.__timeToMins(end_time) + renew_info["expect_duration"]*60
|
||||
try:
|
||||
WebDriverWait(self.__driver, 2).until(
|
||||
EC.visibility_of_element_located((By.ID, "extendDiv"))
|
||||
)
|
||||
WebDriverWait(self.__driver, 2).until(
|
||||
EC.presence_of_all_elements_located(
|
||||
(By.CSS_SELECTOR, "#extendDiv .renewal_List li")
|
||||
)
|
||||
)
|
||||
renew_ok_btn = WebDriverWait(self.__driver, 2).until(
|
||||
EC.presence_of_element_located((By.CSS_SELECTOR, "#extendDiv .btnOK"))
|
||||
)
|
||||
except:
|
||||
self._showTrace("续约时间选择界面加载失败 !")
|
||||
return False
|
||||
try:
|
||||
renew_time_opts = self.__driver.find_elements(
|
||||
By.CSS_SELECTOR, "#extendDiv .renewal_List li"
|
||||
)
|
||||
free_times = []
|
||||
best_time_diff = max_diff
|
||||
best_actual_diff = None
|
||||
best_time_opt = None
|
||||
|
||||
if not renew_time_opts:
|
||||
self._showTrace("当前未查询到可用续约时间 !")
|
||||
return False
|
||||
for time_opt in renew_time_opts:
|
||||
time_attr = time_opt.get_attribute("id")
|
||||
if time_attr and time_attr.isdigit():
|
||||
time_val = int(time_attr)
|
||||
free_times.append(time_opt.text.strip())
|
||||
else:
|
||||
continue
|
||||
actual_diff = time_val - target_renew_mins
|
||||
abs_diff = abs(actual_diff)
|
||||
if abs_diff < best_time_diff or (
|
||||
abs_diff == best_time_diff and (
|
||||
# 优先选择更早的时间
|
||||
(prefer_earlier and actual_diff <= 0) or
|
||||
# 优先选择更晚的时间
|
||||
(not prefer_earlier and actual_diff >= 0)
|
||||
)
|
||||
):
|
||||
best_time_diff = abs_diff
|
||||
best_actual_diff = actual_diff
|
||||
best_time_opt = time_opt
|
||||
|
||||
if best_time_opt is not None:
|
||||
best_time_opt.click()
|
||||
abs_time_diff = abs(best_actual_diff)
|
||||
if best_actual_diff < 0:
|
||||
time_relation = f"早了 {abs_time_diff} 分钟"
|
||||
elif best_actual_diff > 0:
|
||||
time_relation = f"晚了 {abs_time_diff} 分钟"
|
||||
else:
|
||||
time_relation = f"正好等于续约时间"
|
||||
self._showTrace(
|
||||
f"选择距离期望续约时间最近的 {best_time_opt.text}, "\
|
||||
f"与期望续约时间相比 {time_relation}"
|
||||
)
|
||||
renew_ok_btn.click()
|
||||
return True
|
||||
self._showTrace(
|
||||
"无法选择最近的可用续约时间 !" \
|
||||
f"所有可选时间与目标时间相差都超过了 {max_diff} 分钟 !"
|
||||
)
|
||||
self._showTrace(
|
||||
f"当前可供续约的时间有: {free_times}"
|
||||
)
|
||||
return False
|
||||
except:
|
||||
self._showTrace("查询可用续约时间时发生未知错误 !")
|
||||
return False
|
||||
|
||||
|
||||
def renew(
|
||||
self,
|
||||
username: str,
|
||||
record: dict,
|
||||
reserve_info: dict
|
||||
) -> bool:
|
||||
|
||||
if self.__driver is None:
|
||||
self._showTrace("未提供有效 WebDriver 实例 !")
|
||||
return False
|
||||
try:
|
||||
renew_btn = WebDriverWait(self.__driver, 2).until(
|
||||
EC.element_to_be_clickable((By.ID, "btnExtend"))
|
||||
)
|
||||
except:
|
||||
self._showTrace(f"用户 {username} 续约界面加载失败 !")
|
||||
return False
|
||||
if "disabled" in renew_btn.get_attribute("class"):
|
||||
self._showTrace(f"用户 {username} 续约按钮不可用, 可能不在场馆内")
|
||||
return False
|
||||
renew_btn.click()
|
||||
if not self.__selectNearstRecord(record, reserve_info):
|
||||
return False
|
||||
# renew_ok_btn.click()
|
||||
if self._waitResponseLoad():
|
||||
self._showTrace(f"用户 {username} 续约成功 !")
|
||||
return True
|
||||
else:
|
||||
self._showTrace(f"用户 {username} 续约失败 !")
|
||||
return False
|
||||
|
||||
@@ -187,12 +187,13 @@ class LibReserve(LibOperator):
|
||||
reserve_info: dict
|
||||
) -> bool:
|
||||
|
||||
if reserve_info.get("expect_duration") is None:
|
||||
reserve_info["expect_duration"] = 4
|
||||
self._showTrace("预约持续时间未指定, 使用默认时长为 4 小时")
|
||||
if reserve_info.get("satisfy_duration") is None:
|
||||
reserve_info["satisfy_duration"] = True
|
||||
self._showTrace("预约满足时长要求未指定, 默认满足")
|
||||
if reserve_info["satisfy_duration"]:
|
||||
if reserve_info.get("expect_duration") is None:
|
||||
reserve_info["expect_duration"] = 4
|
||||
self._showTrace("需要满足预约持续时间, 但未指定, 使用默认时长为 4 小时")
|
||||
return True
|
||||
|
||||
|
||||
@@ -234,7 +235,7 @@ class LibReserve(LibOperator):
|
||||
# if end time is earlier than begin_time, exchange them
|
||||
if end_mins < begin_mins:
|
||||
self._showTrace(
|
||||
f"结束时间 {end_time['time']} 早于开始时间 {begin_time['time']}, 自动交换"
|
||||
f"结束时间 {end_time['time']} 早于开始时间 {begin_time['time']}, 尝试交换时间"
|
||||
)
|
||||
reserve_info["end_time"] = begin_time
|
||||
reserve_info["begin_time"] = end_time
|
||||
@@ -261,10 +262,9 @@ class LibReserve(LibOperator):
|
||||
if end_mins - begin_mins > 8*60:
|
||||
self._showTrace(
|
||||
f"该用户未设置优先满足时长要求, 但是检查到预约持续时间 "
|
||||
f"{int((end_mins - begin_mins)/60)} 小时 "
|
||||
f"{float((end_mins - begin_mins)/60)} 小时 "
|
||||
f"超出最大时长 8 小时, 自动设置为 8 小时"
|
||||
)
|
||||
reserve_info["expect_duration"] = 8
|
||||
reserve_info["end_time"]["time"] = self.__minsToTime(begin_mins + 8*60)
|
||||
return True
|
||||
|
||||
@@ -577,6 +577,7 @@ class LibReserve(LibOperator):
|
||||
expect_begin_time = actual_begin_time = begin_time["time"]
|
||||
expect_end_time = actual_end_time = end_time["time"]
|
||||
expect_begin_mins = self.__timeToMins(expect_begin_time)
|
||||
actual_begin_mins = expect_begin_mins
|
||||
expect_end_mins = self.__timeToMins(expect_end_time)
|
||||
|
||||
# select the begin time
|
||||
@@ -590,11 +591,18 @@ class LibReserve(LibOperator):
|
||||
return False
|
||||
else:
|
||||
actual_begin_time = self.__minsToTime(expect_begin_mins)
|
||||
actual_begin_mins = self.__timeToMins(actual_begin_time)
|
||||
# if 'satisfy_duration' is True.
|
||||
# select the end time based on the begin time
|
||||
# (because it may be changed under the 'max time diff' strategy) and expect duration.
|
||||
if satisfy_duration:
|
||||
expect_end_mins = int(expect_begin_mins + expct_duration*60)
|
||||
expect_end_mins = int(actual_begin_mins + expct_duration*60)
|
||||
if expect_end_mins > self.__timeToMins("23:30"):
|
||||
expect_end_mins = self.__timeToMins("23:30")
|
||||
self._showTrace(
|
||||
f"预约持续时间 {expct_duration} 小时, 超过最大预约时间 23:30, 自动调整为 23:30"
|
||||
)
|
||||
expect_end_time = self.__minsToTime(expect_end_mins)
|
||||
self._showTrace(
|
||||
f"需要满足期望预约持续时间: {expct_duration} 小时, "\
|
||||
f"根据开始时间 {actual_begin_time} 计算结束时间: {self.__minsToTime(expect_end_mins)}"
|
||||
@@ -674,4 +682,8 @@ class LibReserve(LibOperator):
|
||||
self._showTrace(f"预约提交失败 !")
|
||||
if not submit_reserve and have_hover_on_page:
|
||||
self.__driver.refresh()
|
||||
if reserve_success:
|
||||
self._showTrace(f"用户 {reserve_info['username']} 预约成功 !")
|
||||
else:
|
||||
self._showTrace(f"用户 {reserve_info['username']} 预约失败 !")
|
||||
return reserve_success
|
||||
Reference in New Issue
Block a user