401c879ffd
Auto-complete EF English courses with JWT token authentication. Supports multiple task types: multiple-choice, gapfill, matching, flashcards, speaking-practice, text-highlights, sequencing, media-with-time-markers, language-focus. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
130 lines
3.8 KiB
Python
Executable File
130 lines
3.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
"""
|
||
EF Course Autopilot — 交互式循环运行脚本
|
||
|
||
从 token.txt 文件读取 JWT token(默认读取运行目录下的 token.txt)。
|
||
token 需从浏览器开发者工具中获取,详见 README.md。
|
||
|
||
用法示例:
|
||
python3 ef_course_loop.py # 默认读取 ./token.txt
|
||
python3 ef_course_loop.py --token-file /path/to/token.txt
|
||
"""
|
||
|
||
import argparse
|
||
import sys
|
||
import time
|
||
|
||
from ef_course_autopilot import EFCourseAutopilot
|
||
|
||
|
||
def read_token(token_file: str) -> str:
|
||
"""从指定文件读取 token(仅支持单行内容)"""
|
||
try:
|
||
with open(token_file, "r") as f:
|
||
token = f.read().strip()
|
||
if not token:
|
||
print(f"❌ token 文件为空: {token_file}")
|
||
sys.exit(1)
|
||
print(f" 📄 从文件读取 token ({token_file})")
|
||
return token
|
||
except FileNotFoundError:
|
||
print(f"❌ token 文件不存在: {token_file}")
|
||
print(f" 请创建 {token_file} 并将 ef_access_token 粘贴到第一行")
|
||
sys.exit(1)
|
||
except IOError as e:
|
||
print(f"❌ 读取文件失败: {e}")
|
||
sys.exit(1)
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(
|
||
description="EF Course Autopilot — 交互式循环运行",
|
||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||
epilog="""\
|
||
使用示例:
|
||
python3 ef_course_loop.py # 默认读取 ./token.txt
|
||
python3 ef_course_loop.py --token-file /path/to/token.txt
|
||
|
||
token.txt 说明:
|
||
- 仅能包含一行,即 ef_access_token 的值
|
||
- 从浏览器开发者工具中取请求携带的 ef_access_token 内容,手动粘贴
|
||
""",
|
||
)
|
||
parser.add_argument(
|
||
"--token-file",
|
||
default="token.txt",
|
||
help="从文件读取 JWT token(默认: ./token.txt)",
|
||
)
|
||
parser.add_argument(
|
||
"--verify-ssl",
|
||
action="store_true",
|
||
help="启用SSL证书验证(默认禁用)",
|
||
)
|
||
|
||
args = parser.parse_args()
|
||
|
||
print("=" * 60)
|
||
print(" EF Course Autopilot — 交互式循环运行")
|
||
print("=" * 60)
|
||
|
||
while True:
|
||
# 1. 从文件获取 token
|
||
token = read_token(args.token_file)
|
||
|
||
# 2. 输入课程数量
|
||
while True:
|
||
try:
|
||
count_str = input("请输入要完成的课程数量: ").strip()
|
||
count = int(count_str)
|
||
if count <= 0:
|
||
print("❌ 数量必须大于 0")
|
||
continue
|
||
break
|
||
except ValueError:
|
||
print("❌ 请输入有效数字")
|
||
|
||
# 3. 循环完成课程
|
||
total_success = 0
|
||
total_fail = 0
|
||
start_time = time.time()
|
||
|
||
for i in range(count):
|
||
print(f"\n{'=' * 60}")
|
||
print(f" 第 {i + 1}/{count} 门课程")
|
||
print(f"{'=' * 60}")
|
||
|
||
autopilot = EFCourseAutopilot(
|
||
token=token,
|
||
skip_on_fail=True,
|
||
verify_ssl=args.verify_ssl,
|
||
)
|
||
|
||
try:
|
||
success = autopilot.run()
|
||
if success:
|
||
total_success += 1
|
||
else:
|
||
total_fail += 1
|
||
except Exception as e:
|
||
print(f"\n❌ 课程执行异常: {e}")
|
||
total_fail += 1
|
||
|
||
elapsed = time.time() - start_time
|
||
print(f"\n{'#' * 60}")
|
||
print(f" 本轮完成!")
|
||
print(f" 计划: {count} 门")
|
||
print(f" ✅ 成功: {total_success}")
|
||
print(f" ❌ 失败: {total_fail}")
|
||
print(f" ⏱️ 耗时: {elapsed:.1f}秒")
|
||
print(f"{'#' * 60}")
|
||
|
||
# 4. 询问是否继续
|
||
again = input("\n是否继续?(y/n): ").strip().lower()
|
||
if again != "y":
|
||
print("\n程序结束。")
|
||
break
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|