---
# System prepended metadata

title: 開源專案更新
tags: [淡江大學搶課機器人開源專案]

---

###### tags: `淡江大學搶課機器人開源專案`
# 開源專案230830更新
## 前言：
搶課機器人在3月放出來後收到廣大的迴響，但最近Chrome更新，修改了呼叫的方式，舊的機器人已經不能使用了，所以這幾天寫了一個新版的並且新增了一些功能，也感謝新生跟轉學生讓我有機會測試，經過測試後可以正常使用，一樣多平台支援，**但intel版的Mac系統晚上才會更新**

## 適用環境：
* Mac intel 處理器：**macOS 13.5.1以上都可以使用
* Mac Apple Silicon 處理器：**macOS 13.5.1**以上都可以使用
* Windows 系統：**Windows 10**以上都可以使用


## 使用方式：
### 1. 先進資料夾下載執行檔案
[下載位置](https://1drv.ms/u/s!AvwcoqTkdjpWg6gp_bPQIFFvSRJ8nQ?e=K7QFC6)
> Windows平台請下載Public_WYSHBot_230829_Windows
> MacOS Intel處理器的請下載Public_WYSHBot_230829_Mac(intel)
> MacOS M1/M2系列處理器請下載Public_WYSHBot_230829_MacOS(Silicon)


### 2. 開始執行搶課機器人
* Windows直接點擊start.bat
![](https://i.imgur.com/EaUWGCb.jpg)

* Mac系列直接下載後解壓縮直接放到應用程式資料夾中，點兩下執行
![](https://i.imgur.com/eiQkxQj.png)
* 若Mac無法成功執行請參考備註1
* 在230829有修改圖示，請以實際圖示為主

### 3. 設定基本資料(Windows/Mac使用方式相同)
![](https://hackmd.io/_uploads/Ska5BE2an.png)
* 先設定登入資訊(務必按下儲存登入資訊)
* 設定加退選資訊
* 設定完加退選資訊務必按下儲存加退選清單
* **注意，如果沒有使用ChromeDriver的需求，7.就直接使用推薦的不用修改**

### 4. 執行搶課程式(Windows/Mac使用方式相同)
![](https://i.imgur.com/TQmVgpA.png)
* 按下執行搶課主程式

### 5. 設定搶課程式(Windows/Mac使用方式相同)
![](https://hackmd.io/_uploads/B1U5842T2.png)
* 先設定語言
* 再設定是要立即搶課或是預約搶課
* 完成後，執行開始搶課

### 6. 剩下交給上蒼
補充說明：機器人會隨機延遲幾秒鐘，一來是因為學校系統有時候會當機，二來是因為要保障有購買機器人的使用者權利

### Demo影片：
![](https://i.imgur.com/fHAJqUY.jpg)
https://youtu.be/iINclOsUYpI
備註，影片中使用Mac做範例，Windows使用介面大同小異

### 備註1(開啟任何來源)：
* 請開啟任終端機：
![](https://i.imgur.com/jJsZZBc.png)

* 在終端機中打入以下指令：
![](https://i.imgur.com/Qbtf4bJ.png)
sudo spctl --master-disable

* 打入密碼(請注意這個密碼不會顯示)：
![](https://i.imgur.com/GOy8pHy.png)

* 打開設定中的隱私權與安全性：
![](https://i.imgur.com/HiaNSls.png)

## 進階功能
本機器人有Premium版本，提供以下功能：
* 完整的搶課速度
* 極速刷課模式
* 單一裝置登入功能
* 帳號密碼加密，強化安全性
![](https://i.imgur.com/46z1OqC.png)

若有需要，可以點擊以下連結：
![](https://hackmd.io/_uploads/rJ9nP4362.png)
![](https://hackmd.io/_uploads/H1Xb_N3T3.jpg)

[https://line.me/ti/g2/EQSB4VBKjoVXM0n46GDIrmdTwieWd1LIrtYpJg?utm_source=invitation&utm_medium=link_copy&utm_campaign=default](https://line.me/ti/g2/EQSB4VBKjoVXM0n46GDIrmdTwieWd1LIrtYpJg?utm_source=invitation&utm_medium=link_copy&utm_campaign=default)

## 原始碼開源
以下為原始碼，可以直接下載原始檔案使用
打包：
https://1drv.ms/u/s!AvwcoqTkdjpWg7thc2Y4Pm72H_xErg?e=subqq4

##### setting.py
```
import os
import subprocess
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
from tkinter.constants import *

import cryptocode
import sys
import threading
import platform
global ScrollBar
global window
window = tk.Tk()
global AddToList_Action
AddToList_Action = []
global AddToList_OpenCourse
AddToList_OpenCourse = []
global ExchangeFirst
ExchangeFirst = 0
global ExchangeSecond
ExchangeSecond = 0
global RemoveItem
RemoveItem = 0
working_dir = os.path.dirname(os.path.realpath(__file__))
global Login_Path
Login_Path = working_dir+"/Module_Addition/ProgramPlugin_1.info"
global Selective_Path
Selective_Path = working_dir+"/Module_Addition/ProgramPlugin_2.info"
global SelectionMode_Path
SelectionMode_Path = working_dir+"/Module_Addition/ProgramPlugin_3.info"
Record = 0

def LoadTheLoginInformation():
    global Record,Login_Path
    try:
        with open(Login_Path, 'r') as f:
            global Login
            Login = f.read().splitlines()
            for i in range(len(Login)):
                if (i+1)==1 or (i+1)==3:
                    pass
                elif (i+1)==2:
                    global Account_Login_Record
                    Account_Login_Record = str(Login[i])#解密
                    Account_textbox.insert(0, Account_Login_Record)
                    Record = 1
                else:
                    global Password_Login_Record
                    Password_Login_Record = str(Login[i])#解密
                    Password_textbox.insert(0, Password_Login_Record)
    except FileNotFoundError:
        Record = 0
        messagebox.showinfo("提示","偵測到程式遭修改\n請聯絡負責人")
        os._exit()
    return
def LoginSavingInformation():
    global Record
    global Account
    Account = Account_textbox.get()#加密
    #print(Account)
    Password = Password_textbox.get()#加密
    #print(Password)
    global Login_Path
    try:
        if(Account!="" and Password!= ""):
            with open(Login_Path, 'w') as f:
                f.write('Account')
                f.write('\n')
                f.write(Account)
                f.write('\n')
                f.write('Password')
                f.write('\n')
                f.write(Password)
                Record = 1
        else:
            messagebox.showinfo("提示", "輸入錯誤請重試")

    except:
        messagebox.showinfo("提示", "我們偵測到了你嘗試修改程式\n請聯絡負責人")
        os._exit()

def SelectiveSaving():
    global Selective_Path
    try:
        if (Selective_Path):
            with open(Selective_Path, 'w') as f:
                f.write('')
            for i in range(len(AddToList_Action)):
                with open(Selective_Path, 'a') as f:
                    f.write(AddToList_Action[i])
                    f.write('\n')
                    f.write(AddToList_OpenCourse[i])
                    f.write('\n')
            messagebox.showinfo("提示","選課清單儲存成功")
        else:
            messagebox.showinfo("提示","儲存路徑錯誤請重試")
    except:
        messagebox.showinfo("提示", "我們偵測到了您嘗試修改過程式\n請聯絡搶課負責人")
    return
def LoadSelectivedList():
    global Selective_Path
    try:
        with open(Selective_Path, 'r') as f:
            global Selection
            Selection = f.read().splitlines()
            for i in range(len(Selection)):
                if (i+1)%2==1:
                    AddToList_Action.append(str(Selection[i]))
                elif (i+1)%2==0:
                    AddToList_OpenCourse.append(str(Selection[i]))
    except FileNotFoundError:
        pass
    return
def LoginInformatioSavingConfirmBox():
    global Record
    Account = Account_textbox.get()
    Password = Password_textbox.get()
    if (Record==1 and Account !="" and Password !=""):
        LoginSavingInformation()
        messagebox.showinfo("提示", "密碼更新成功")
    elif Account =="" or Password =="":
        messagebox.showinfo("提示", "學號或密碼不能留空")
    elif (Record==0 and Account !="" and Password !=""):
        '''MsgBox = tk.messagebox.askquestion("提示","請問你確定儲存學號密碼嗎?\n學號只能綁定一次喔!\n學號未來是不能修改\n\nP.S.密碼可以修改")
        if MsgBox =="yes":
            LoginSavingInformation()
            Account_textbox.config(state='disable')
            messagebox.showinfo("提示", "學號密碼設定成功")
        else:
            pass'''
        messagebox.showinfo("提示", "學號密碼設定成功")
def build_GUI():
    #Build A GUI Window
    window.title("選課設定")
    window.geometry('380x540')
    window.resizable(False, True)

    #LoginTitle
    LoginTitle = tk.Label(window,width=30,text="登入資訊",font=("normal",15),compound="center")
    LoginTitle.place(x=190,y=20,anchor=CENTER)
    AccountInformation()
    PasswordInformation()

    #Button
    #LoginSaving Button
    Save_Button = tk.Button(text="儲存登入資訊",command=LoginInformatioSavingConfirmBox)
    Save_Button.place(x=190, y=115, anchor=CENTER)
    LoadTheLoginInformation()

    #SelectiveSaving_Button
    #SelectiveTitle
    SelectiveTitle = tk.Label(width=30,text="加退選資訊",font=("normal",15),compound="center")
    SelectiveTitle.place(x=190, y=165, anchor=CENTER)
    LoadSelectivedList()
    showList()
    Options()
    window.mainloop()

#Login Information
def AccountInformation():
    #Account
    Label_Account_textbox = tk.Label(width=6,text="學號",compound="center")
    Label_Account_textbox.place(x=60,y=40)
    global Account_textbox
    Account_textbox = tk.Entry(window)
    Account_textbox.pack()
    Account_textbox.place(x=120,y=40)
def PasswordInformation():
    # Password
    Label_Password_textbox = tk.Label(width=6, text="密碼", compound="center")
    Label_Password_textbox.place(x=60,y=70)
    global Password_textbox
    Password_textbox = tk.Entry(window)
    Password_textbox.pack()
    Password_textbox.place(x=120,y=70)

#Action
def Drop():
    Remove_Target = int(Revise_Remove_Box.get()) - 1
    if (Remove_Target<len(AddToList_Action) and Remove_Target>=0):
        initial()
        AddToList_Action.pop(Remove_Target)
        AddToList_OpenCourse.pop(Remove_Target)
        #Clear TextBox
        Revise_Remove_Box.delete(0, END)
        showList()
        #messagebox.showinfo("提示", "刪除成功")
    else:
        messagebox.showinfo("提示", "輸入錯誤，請重試")
    return
def Exchange():
    FirstIndex = int(Revise_ExchangeFirst_Box.get()) - 1
    SecondIndex = int(Revise_ExchangeSecond_Box.get()) - 1
    if (FirstIndex < len(AddToList_Action) and FirstIndex >= 0 and SecondIndex < len(AddToList_Action) and SecondIndex >= 0 and SecondIndex!= FirstIndex):
        AddToList_Action[FirstIndex], AddToList_Action[SecondIndex] = AddToList_Action[SecondIndex], AddToList_Action[FirstIndex]
        AddToList_OpenCourse[FirstIndex], AddToList_OpenCourse[SecondIndex] = AddToList_OpenCourse[SecondIndex], AddToList_OpenCourse[FirstIndex]
        # Clear TextBox
        Revise_ExchangeFirst_Box.delete(0, END)
        Revise_ExchangeSecond_Box.delete(0, END)
        showList()
        messagebox.showinfo("提示", "交換成功")
    else:
        messagebox.showinfo("提示", "輸入錯誤，請重試")
    return
def initial():
    y_axis = 270
    for i in range(len(AddToList_Action)):
        y_axis = y_axis + 30
        temp = tk.Label(window,width=2,height=3,text="",font=("normal",10),compound="center")
        temp.pack()
        temp.place(x=55,y=y_axis,anchor=CENTER)

        temp_1 = tk.Label(window,width=7,height=3,text="",font=("normal",10),compound="center")
        temp_1.pack()
        temp_1.place(x=100,y=y_axis,anchor=CENTER)

        temp_2 = tk.Label(window, width=7,height=3,text="", font=("normal",10),compound="center")
        temp_2.pack()
        temp_2.place(x=170, y=y_axis,anchor=CENTER)

#Selective Information
def Options():
    # Options
    global Optional_Selective
    Optional_Selective = ttk.Combobox(window,state="readonly", width=5, values=["加選", "退選"])
    Optional_Selective.pack()
    Optional_Selective.place(x=100, y=195, anchor=CENTER)
    Optional_Selective.current(0)

    #OpenCourseBox
    global OpenCourseBox
    OpenCourseBox = tk.Entry(window,width=15)
    OpenCourseBox.pack()
    OpenCourseBox.place(x=220,y=195,anchor=CENTER)

    #AddButton
    AddButton = tk.Button(text="加入清單",command=AddToList)
    AddButton.place(x=190, y=225, anchor=CENTER)

    #================================================================================================================
    #List
    Number_Column = tk.Label(window,width=2,height=3,text="#",font=("normal",10),compound="center")
    Number_Column.pack()
    Number_Column.place(x=55,y=270,anchor=CENTER)

    Action_Column = tk.Label(window,width=7,height=3,text="操作",font=("normal",10),compound="center")
    Action_Column.pack()
    Action_Column.place(x=100,y=270,anchor=CENTER)

    CourseCode_Column = tk.Label(window, width=7,height=3, font=("normal",10), text="開課代碼",compound="center")
    CourseCode_Column.pack()
    CourseCode_Column.place(x=170, y=270,anchor=CENTER)

    #================================================================================================================
    #ReviseArea
    #ReviseTitle
    Revise_Column = tk.Label(window, width=20, height=3, font=("normal", 10), text="調整", compound="center")
    Revise_Column.pack()
    Revise_Column.place(x=300, y=270, anchor=CENTER)

    #ReviseFirst_#
    Revise_ExchangeFirst = tk.Label(window, width=2, height=1, font=("normal", 10), text="#", compound="center")
    Revise_ExchangeFirst.pack()
    Revise_ExchangeFirst.place(x=220, y=300, anchor=CENTER)

    #ReviseFirst_TextBox
    global Revise_ExchangeFirst_Box
    Revise_ExchangeFirst_Box = tk.Entry(window, width=3)
    Revise_ExchangeFirst_Box.pack()
    Revise_ExchangeFirst_Box.place(x=240, y=300, anchor=CENTER)

    #ReviseSecond_#
    Revise_ExchangeSecond = tk.Label(window, width=2, height=1, font=("normal", 10), text="#", compound="center")
    Revise_ExchangeSecond.pack()
    Revise_ExchangeSecond.place(x=270, y=300, anchor=CENTER)

    #ReviseSecond_TextBox
    global Revise_ExchangeSecond_Box
    Revise_ExchangeSecond_Box = tk.Entry(window, width=3)
    Revise_ExchangeSecond_Box.pack()
    Revise_ExchangeSecond_Box.place(x=290, y=300, anchor=CENTER)

    #ExchangeButton
    ExchangeButton = tk.Button(text="交換", command=Exchange)
    ExchangeButton.place(x=340, y=300, anchor=CENTER)

    #Remove_#
    Revise_Remove = tk.Label(window, width=2, height=1, font=("normal", 10), text="#", compound="center")
    Revise_Remove.pack()
    Revise_Remove.place(x=250, y=330, anchor=CENTER)

    #Remove_TextBox
    global Revise_Remove_Box
    Revise_Remove_Box = tk.Entry(window, width=3)
    Revise_Remove_Box.pack()
    Revise_Remove_Box.place(x=275, y=330, anchor=CENTER)

    #Remove_Button
    Remove_Button = tk.Button(text=U"刪除", command=Drop)
    Remove_Button.place(x=330, y=330, anchor=CENTER)

    #================================================================================================================
    #Saving Area
    #SavingTitle
    Saving_Column = tk.Label(window, width=20, height=2, font=("normal", 10), text=U"儲存", compound="center")
    Saving_Column.pack()
    Saving_Column.place(x=300, y=370, anchor=CENTER)

    #SavingButton
    SavingButton = tk.Button(text=U"儲存加退選清單", command=SelectiveSaving)
    SavingButton.place(x=300, y=390, anchor=CENTER)

    # ================================================================================================================
    # Execution Area
    # ExecutionTitle
    Execution_Column = tk.Label(window, width=20, height=2, font=("normal", 10), text=U"搶課", compound="center")
    Execution_Column.pack()
    Execution_Column.place(x=300, y=420, anchor=CENTER)

    # ExecutionButton
    global Execution_Mode
    Execution_Mode = ttk.Combobox(window, state="readonly", width=15, values=["UC模式(推薦)","ChromeDriver"])
    Execution_Mode.pack()
    Execution_Mode.place(x=300, y=450, anchor=CENTER)
    Execution_Mode.current(0)
    ExecutionButton = tk.Button(text=U"執行搶課主程式", command=ExecutionMainFunction)
    ExecutionButton.place(x=300, y=480, anchor=CENTER)

def AddToList():
    if  Optional_Selective.get() == "加選" and OpenCourseBox.get() !="":
        AddToList_Action.append("Add")
        AddToList_OpenCourse.append(OpenCourseBox.get())
        OpenCourseBox.delete(0, END)
        showList()
    elif Optional_Selective.get() == "退選" and OpenCourseBox.get() !="":
        AddToList_Action.append("Remove")
        AddToList_OpenCourse.append(OpenCourseBox.get())
        OpenCourseBox.delete(0, END)
        showList()
    elif Optional_Selective.get() == "刷課" and OpenCourseBox.get() !="":
        AddToList_Action.append("Cycle")
        AddToList_OpenCourse.append(OpenCourseBox.get())
        OpenCourseBox.delete(0, END)
        showList()
    else:
        messagebox.showinfo("提示","開課代碼不能為空白")

def showList():
    y_axis = 270
    for i in range(len(AddToList_Action)):
        y_axis = y_axis + 30
        temp = tk.Label(window,width=2,height=3,text=i+1,font=("normal",10),compound="center")
        temp.pack()
        temp.place(x=55,y=y_axis,anchor=CENTER)

        temp_1 = tk.Label(window,width=7,height=3,text=AddToList_Action[i],font=("normal",10),compound="center")
        temp_1.pack()
        temp_1.place(x=100,y=y_axis,anchor=CENTER)

        temp_2 = tk.Label(window, width=7,height=3,text=AddToList_OpenCourse[i], font=("normal",10),compound="center")
        temp_2.pack()
        temp_2.place(x=170, y=y_axis,anchor=CENTER)

    #print(y_axis)
    if (y_axis>=480):
        wide = 380
        height = str(540+(len(AddToList_Action)-7)*30)
        mix = str(wide)+"x"+height
        window.geometry(mix)
    return

def LoginInformationCheck():
    CurrentAccount = Account_textbox.get()
    CurrentPassword = Password_textbox.get()
    global Login_Path

    with open(Login_Path, 'r') as f:
        global Login
        Login = f.read().splitlines()
        for i in range(len(Login)):
            if (i + 1) == 1 or (i + 1) == 3:
                pass
            elif (i + 1) == 2:
                global Account_Login_Record
                Account_Login_Record = str(Login[i])  # 解密
            else:
                global Password_Login_Record
                Password_Login_Record = str(Login[i])  # 解密
        try:
            if Account_Login_Record != CurrentAccount or Password_Login_Record != CurrentPassword :
                messagebox.showinfo("提示", "請儲存帳號密碼")
                return False
        except NameError:
            messagebox.showinfo("提示", "請設定帳號密碼")
            return False
        return True

def launch_MainFunction():
    try:
        subprocess.Popen(working_dir + "/Module_Addition/main", shell=True)
    except:
        subprocess.Popen(working_dir + "/Module_Addition/main.exe", shell=True)

def ExecutionMainFunction():
    if(LoginInformationCheck()):
        global working_dir,SelectionMode_Path
        if(Execution_Mode.get()=="UC模式(推薦)"):
            with open(SelectionMode_Path, 'w') as f:
                f.write('')
                f.write('UCMode')
        else:
            with open(SelectionMode_Path, 'w') as f:
                f.write('')
                f.write('ChromeDriverMode')
        if hasattr(sys, 'frozen'):
            threading.Thread(target=launch_MainFunction).start()
        else:
            try:
                s = subprocess.Popen(['python3', 'main' + '.py'], cwd=working_dir+'/Module_Addition')
            except:
                s = subprocess.Popen(['python', 'main' + '.py'], cwd=working_dir+'/Module_Addition')
    else:
        pass

#main function
if __name__ == '__main__':
    build_GUI()
```
##### main.py
```
import os
import datetime
import os
import random
import ssl
import time
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
from tkinter.constants import *
from tkinter import filedialog

import cryptocode
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service as ChromeService
import chromedriver_autoinstaller
ssl._create_default_https_context = ssl._create_unverified_context

URL_Chinese = "https://www.ais.tku.edu.tw/EleCos/login.aspx?ReturnUrl=%2felecos%2f"
URL_English = "https://www.ais.tku.edu.tw/EleCos_English/loginE.aspx"

global ChineseScript
ChineseScript = "javascript: (function(){ var numHash={b6589fc6ab0dc82cf12099d1c2d40ab994e8410c:\"0\",\"356a192b7913b04c54574d18c28d46e6395428ab\":\"1\",da4b9237bacccdf19c0760cab7aec4a8359010b0:\"2\",\"77de68daecd823babbb58edb1c8e14d7106e83bb\":\"3\",\"1b6453892473a467d07372d45eb05abc2031647a\":\"4\",ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4:\"5\",c1dfd96eea8cc2b62785275bca38ac261256e278:\"6\",\"902ba3cda1883801594b6e1b452790cc53948fda\":\"7\",fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f:\"8\",\"0ade7c2cf97f75d009975f4d720d1fa6c19f4897\":\"9\"};$.ajax({url:\"https://www.ais.tku.edu.tw/EleCos/Handler1.ashx\",type:\"post\",async:false,success:function(voice){document.getElementById(\"txtCONFM\").value=numHash[voice[0]]+numHash[voice[1]]+numHash[voice[2]]+numHash[voice[3]]+numHash[voice[4]]+numHash[voice[5]];}}); })();"
global EnglishScript
EnglishScript = "javascript: (function(){ var numHash={b6589fc6ab0dc82cf12099d1c2d40ab994e8410c:\"0\",\"356a192b7913b04c54574d18c28d46e6395428ab\":\"1\",da4b9237bacccdf19c0760cab7aec4a8359010b0:\"2\",\"77de68daecd823babbb58edb1c8e14d7106e83bb\":\"3\",\"1b6453892473a467d07372d45eb05abc2031647a\":\"4\",ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4:\"5\",c1dfd96eea8cc2b62785275bca38ac261256e278:\"6\",\"902ba3cda1883801594b6e1b452790cc53948fda\":\"7\",fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f:\"8\",\"0ade7c2cf97f75d009975f4d720d1fa6c19f4897\":\"9\"};$.ajax({url:\"https://www.ais.tku.edu.tw/EleCos_English/Handler1.ashx\",type:\"post\",async:false,success:function(voice){document.getElementById(\"txtCONFM\").value=numHash[voice[0]]+numHash[voice[1]]+numHash[voice[2]]+numHash[voice[3]]+numHash[voice[4]]+numHash[voice[5]];}}); })();"
global window
window = tk.Tk()

global AddToList_Action
AddToList_Action = []
global AddToList_OpenCourse
AddToList_OpenCourse = []
Account_Login_Record = 0
Password_Login_Record = 0
working_dir = os.path.dirname(os.path.realpath(__file__))
global Login_Path
Login_Path = working_dir+"/ProgramPlugin_1.info"
global Selective_Path
Selective_Path = working_dir+"/ProgramPlugin_2.info"
global SelectionMode_Path
SelectionMode_Path = working_dir+"/ProgramPlugin_3.info"
chromedriver_autoinstaller.install()
global SelectionMode
global driver

# Check select Mode
with open(SelectionMode_Path, 'r') as f:
    global SelectionMode
    SelectionMode = f.read().splitlines()
    SelectionMode = str(SelectionMode[0])

def OpenChrome():
    global driver,Driver_Path
    if (SelectionMode == "UCMode"):
        service = ChromeService()
        options = webdriver.ChromeOptions()
        driver = webdriver.Chrome(service=service,options=options)
    else:
        messagebox.showinfo("提示", "請選取ChromeDriver檔案")
        ChromeDriver_path = filedialog.askopenfilename()  # 選擇檔案後回傳檔案路徑與名稱
        service = ChromeService(executable_path=ChromeDriver_path)
        # print(ChromeDriver_path)
        driver = webdriver.Chrome(service=service)


def LoadTheLoginInformation():
    global Login_Path
    try:
        with open(Login_Path, 'r') as f:
            global Login
            Login = f.read().splitlines()
            for i in range(len(Login)):
                if (i+1)==1 or (i+1)==3:
                    pass
                elif (i+1)==2:
                    global Account_Login_Record
                    Account_Login_Record = str(Login[i])
                    #print("Account: "+Account_Login_Record,type(Account))
                    #print(line[i],type(line[i]))
                else:
                    global Password_Login_Record
                    Password_Login_Record = str(Login[i])
                    #print("Password: "+Password_Login_Record)
    except FileNotFoundError:
        messagebox.showinfo("提示", "無法載入登入資訊"+"\n"+"請先執行setting設定加退選資訊")
    if len(Login)==0:
        messagebox.showinfo("提示","沒有登入資訊"+"\n"+"請先執行setting設定登入資訊")
    return
def LoadTheSelectionInformation():
    global Selective_Path
    try:
        with open(Selective_Path, 'r') as f:
            global Selection
            Selection = f.read().splitlines()
            for i in range(len(Selection)):
                if (i+1)%2==1:
                    if str(Selection[i]) =="Add" or str(Selection[i]) =="Remove":
                        AddToList_Action.append(str(Selection[i]))
                    elif str(Selection[i]) =="Cycle":
                        pass
                elif (i+1)%2==0:
                    AddToList_OpenCourse.append(str(Selection[i]))
                else:
                    pass

    except FileNotFoundError:
        messagebox.showinfo("提示", "無法載入加退選清單"+"\n"+"請先執行setting設定加退選資訊")
        os._exit()
    if len(Selection)==0:
        messagebox.showinfo("提示","加退選清單為空白"+"\n"+"請先執行setting設定加退選資訊")
        os._exit()
    return
def build_GUI():
    #Build A GUI Window
    LoadTheLoginInformation()
    LoadTheSelectionInformation()
    window.title("搶課程式")
    window.geometry('380x440')
    window.resizable(False, True)

    #LanguageTitle
    LanguageTitle = tk.Label(window,width=30,text="語言選擇",font=("normal",15),compound="center")
    LanguageTitle.place(x=190,y=20,anchor=CENTER)
    LanguageSelect()

    #TimeTitle
    SelectiveTitle = tk.Label(window,width=30,text="搶課排程",font=("normal",15),compound="center")
    SelectiveTitle.place(x=190, y=80, anchor=CENTER)
    TimeMode()
    initial()

    #Execution Button
    ExecutionButton = tk.Button(window,text="開始搶課", command=Execution)
    ExecutionButton.place(x=190, y=320, anchor=CENTER)

    #AboutMe
    AboutMeTitle = tk.Label(window, text="~本機器人由淡江大學 資汛工程學系 WYSH 開發製作~", font=("normal", 10), compound="center")
    AboutMeTitle.place(x=190, y=350, anchor=CENTER)
    CompilerTitle = tk.Label(window, text="使用Python3.11.4開發製作，2023/08/28編譯", font=("normal", 10),compound="center")
    CompilerTitle.place(x=190, y=370, anchor=CENTER)
    SloganTitle = tk.Label(window, text="電腦怪傑，實力不容小覷，不服來戰", font=("normal", 10),compound="center")
    SloganTitle.place(x=190, y=390, anchor=CENTER)
    SloganTitle_2 = tk.Label(window, text="只有不想搶的課，沒有搶不到的課", font=("normal", 10), compound="center")
    SloganTitle_2.place(x=190, y=410, anchor=CENTER)
    window.mainloop()

def LanguageSelect():
    global var_1
    var_1 = tk.StringVar()
    global Language_Chinese, Language_English
    Language_Chinese = tk.Radiobutton(window,text='中文', command=LaguageSet,var=var_1, value=1)
    Language_English = tk.Radiobutton(window,text='English', command=LaguageSet,var=var_1, value=2)
    Language_Chinese.place(x=100, y=30)
    Language_English.place(x=220, y=30)
def LaguageSet():
    global SelectionMode
    global Language_Set
    global driver
    Language_Set = var_1.get()
    if Language_Set=="1":
        driver.get(URL_Chinese)
    else:
        driver.get(URL_English)
    return
def TimeMode():
    global var_2
    var_2 = tk.StringVar()
    global TimeMode_Immediately, TimeMode_Schedule
    TimeMode_Immediately = tk.Radiobutton(window,text='立即',command=TimeModeSet, var=var_2,value=3)
    TimeMode_Schedule = tk.Radiobutton(window,text='預約搶課',command=TimeModeSet, var=var_2,value=4)
    TimeMode_Immediately.place(x=100, y=100)
    TimeMode_Schedule.place(x=220, y=100)
def TimeModeSet():
    global TimeMode_Set
    TimeMode_Set = var_2.get()
    if TimeMode_Set =="3":
        initial()
    else:
        TimeSetArea()
    return
def initial():
    # TimeAreaTitle
    TimeAreaTitle = tk.Label(window,width=30, state="disable",text="時間設定", font=("normal", 15), compound="center")
    TimeAreaTitle.place(x=190, y=150, anchor=CENTER)

    # YearTitle
    YearTitle = tk.Label(window,width=3, state="disable", text="年份", font=("normal", 10), compound="center")
    YearTitle.place(x=80, y=180, anchor=CENTER)

    # YearSelectionBox
    global YearSelection
    YearSelection = ttk.Combobox(window, state="disable", width=4,
                                 values=["2023", "2024", "2025", "2026", "2027", "2028", "2029", "2030"])
    YearSelection.pack()
    YearSelection.place(x=75, y=200, anchor=CENTER)
    YearSelection.current(0)

    # MonthTitle
    MonthTitle = tk.Label(window,width=3, state="disable", text="月份", font=("normal", 10), compound="center")
    MonthTitle.place(x=125, y=180, anchor=CENTER)

    # MonthSelectionBox
    global MonthSelection
    MonthSelection = ttk.Combobox(window, state="disable", width=2,
                                  values=["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"])
    MonthSelection.pack()
    MonthSelection.place(x=125, y=200, anchor=CENTER)
    MonthSelection.current(0)

    # DateTitle
    DateTitle = tk.Label(window,width=3, state="disable", text="日期", font=("normal", 10), compound="center")
    DateTitle.place(x=170, y=180, anchor=CENTER)

    # DateSelectionBox
    global DateSelection
    DateSelection = ttk.Combobox(window, state="disable", width=2,
                                 values=["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13",
                                         "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26",
                                         "27", "28", "29", "30", "31"])
    DateSelection.pack()
    DateSelection.place(x=170, y=200, anchor=CENTER)
    DateSelection.current(10)

    # HourTitle
    HourTitle = tk.Label(window,width=3, state="disable", text="小時", font=("normal", 10), compound="center")
    HourTitle.place(x=225, y=180, anchor=CENTER)

    # HourSelectionBox
    global HourSelection
    HourSelection = ttk.Combobox(window, state="disable", width=2,
                                 values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
                                         "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"])
    HourSelection.pack()
    HourSelection.place(x=225, y=200, anchor=CENTER)
    HourSelection.current(12)

    # MinutesTitle
    MinutesTitle = tk.Label(window,width=3, state="disable", text="分", font=("normal", 10), compound="center")
    MinutesTitle.place(x=270, y=180, anchor=CENTER)

    # MinutesSelectionBox
    global MinutesSelection
    MinutesSelection = ttk.Combobox(window, state="disable", width=2,
                                    values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11",
                                            "12", "13",
                                            "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
                                            "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37",
                                            "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
                                            "50", "51", "52", "53", "54", "55", "56", "57", "58", "59"])
    MinutesSelection.pack()
    MinutesSelection.place(x=270, y=200, anchor=CENTER)
    MinutesSelection.current(30)

    # SecondTitle
    SecondTitle = tk.Label(window,width=3, state="disable", text="秒", font=("normal", 10), compound="center")
    SecondTitle.place(x=315, y=180, anchor=CENTER)

    # SecondSelectionBox
    global SecondSelection
    SecondSelection = ttk.Combobox(window, state="disable", width=2,
                                   values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11",
                                           "12", "13",
                                           "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
                                           "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37",
                                           "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
                                           "50", "51", "52", "53", "54", "55", "56", "57", "58", "59"])
    SecondSelection.pack()
    SecondSelection.place(x=315, y=200, anchor=CENTER)
    SecondSelection.current(0)
    return
def TimeSetArea():
    # TimeAreaTitle
    TimeAreaTitle = tk.Label(window,width=30, state="normal",text="時間設定", font=("normal", 15), compound="center")
    TimeAreaTitle.place(x=190, y=150, anchor=CENTER)

    #YearTitle
    YearTitle = tk.Label(window,width=3, state="normal", text="年份", font=("normal", 10), compound="center")
    YearTitle.place(x=80, y=180, anchor=CENTER)

    #YearSelectionBox
    global YearSelection
    YearSelection = ttk.Combobox(window, state="readonly",width=4,values=["2023","2024","2025","2026","2027","2028","2029","2030"])
    YearSelection.pack()
    YearSelection.place(x=75, y=200, anchor=CENTER)
    YearSelection.current(0)

    #MonthTitle
    MonthTitle = tk.Label(window,width=3, state="normal", text="月份", font=("normal", 10), compound="center")
    MonthTitle.place(x=125, y=180, anchor=CENTER)

    #MonthSelectionBox
    global MonthSelection
    MonthSelection = ttk.Combobox(window, state="readonly", width=2,values=["01", "02", "03", "04", "05", "06", "07", "08","09","10","11","12"])
    MonthSelection.pack()
    MonthSelection.place(x=125, y=200, anchor=CENTER)
    MonthSelection.current(0)

    #DateTitle
    DateTitle = tk.Label(window,width=3, state="normal", text="日期", font=("normal", 10), compound="center")
    DateTitle.place(x=170, y=180, anchor=CENTER)

    #DateSelectionBox
    global DateSelection
    DateSelection = ttk.Combobox(window, state="readonly", width=2, values=["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31"])
    DateSelection.pack()
    DateSelection.place(x=170, y=200, anchor=CENTER)
    DateSelection.current(10)

    #HourTitle
    HourTitle = tk.Label(window,width=3, state="normal", text="小時", font=("normal", 10), compound="center")
    HourTitle.place(x=225, y=180, anchor=CENTER)

    #HourSelectionBox
    global HourSelection
    HourSelection = ttk.Combobox(window, state="readonly", width=2,values=["00","01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13","14", "15", "16", "17", "18", "19", "20", "21", "22", "23"])
    HourSelection.pack()
    HourSelection.place(x=225, y=200, anchor=CENTER)
    HourSelection.current(12)

    #MinutesTitle
    MinutesTitle = tk.Label(window,width=3, state="normal", text="分", font=("normal", 10), compound="center")
    MinutesTitle.place(x=270, y=180, anchor=CENTER)

    #MinutesSelectionBox
    global MinutesSelection
    MinutesSelection = ttk.Combobox(window, state="readonly", width=2,
                                 values=["00","01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13",
                                         "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59"])
    MinutesSelection.pack()
    MinutesSelection.place(x=270, y=200, anchor=CENTER)
    MinutesSelection.current(30)

    # SecondTitle
    SecondTitle = tk.Label(window,width=3, state="normal", text="秒", font=("normal", 10), compound="center")
    SecondTitle.place(x=315, y=180, anchor=CENTER)

    #SecondSelectionBox
    global SecondSelection
    SecondSelection = ttk.Combobox(window, state="readonly", width=2,
                                    values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11",
                                            "12", "13",
                                            "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25",
                                            "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37",
                                            "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
                                            "50", "51", "52", "53", "54", "55", "56", "57", "58", "59"])
    SecondSelection.pack()
    SecondSelection.place(x=315, y=200, anchor=CENTER)
    SecondSelection.current(0)
    return
def Execution():
    global driver
    try:
        Account(Account_Login_Record)
        Password(Password_Login_Record)
        ConfirmNumber()
        if TimeMode_Set=="3":
            driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click()  # 時間到了會自動幫你按登入
            Selection_Main()
        else:
            TimeSet = YearSelection.get()+"-"+MonthSelection.get()+"-"+DateSelection.get()+" "+HourSelection.get()+":"+MinutesSelection.get()+":"+SecondSelection.get()#str(int(SecondSelection.get())+1)
            TimeCheck(TimeSet)
            Selection_Main()
    except:
        pass
    return
def Selection_Main():
    for i in range(len(AddToList_Action)):
        if AddToList_Action[i]=="Add":
            AddCourse(AddToList_OpenCourse[i])
        elif AddToList_Action[i]=="Remove":
            RemoveCourse(AddToList_OpenCourse[i])
        else:
            pass

#Login information
#StudentID
def Account(Account_Number):
    global driver
    try:
        account = driver.find_element("xpath","//*[@id=\"txtStuNo\"]")
        account.clear()
        account.send_keys(Account_Number)#學號
    except:
        print("系統尚未開放")
    return
#StudentPassword
def Password(Password_Value):
    global driver
    try:
        password = driver.find_element("xpath","//*[@id=\"txtPSWD\"]")
        password.clear()
        password.send_keys(Password_Value)#密碼
    except:
        print("系統尚未開放")
    return
def ConfirmNumber():
    global driver
    #ConfirmNumber
    #try:
    ConfirmNumber = driver.find_element("xpath","//*[@id=\"txtCONFM\"]")
    ConfirmNumber.clear()
    try:
        if Language_Set=="1":
            driver.execute_script(ChineseScript)
        else:
            driver.execute_script(EnglishScript)
    except:
        ConfirmNumber.send_keys("")
    return

def TimeCheck(TIME_SET):
    global driver
    #Check the time
    #格式'2023-01-11 12:29:59'
    #確認加選時間，但拜託格式不要改，空格不要刪除
    try:
        localtime = time.localtime()
        global result
        result = time.strftime("%Y-%m-%d %H:%M:%S", localtime)
        year_check = result[0]+result[1]+result[2]+result[3]
        month_check = result[5]+result[6]
        date_check = result[8]+result[9]
        hour_check = result[11]+result[12]
        minutes_check = result[14]+result[15]
        seconds_check = result[17]+result[18]
        RandomNumber = random.randrange(11)
        current = datetime.datetime(int(year_check),int(month_check),int(date_check),int(hour_check),int(minutes_check),int(seconds_check))
        selection_time_set = datetime.datetime(int(YearSelection.get()),int(MonthSelection.get()),int(DateSelection.get()),int(HourSelection.get()),int(MinutesSelection.get()),int(SecondSelection.get())+RandomNumber)

        #print(current<selection_time_set)
        while current<=selection_time_set:
            localtime = time.localtime()
            result = time.strftime("%Y-%m-%d %H:%M:%S", localtime)
            year_check = result[0] + result[1] + result[2] + result[3]
            month_check = result[5] + result[6]
            date_check = result[8] + result[9]
            hour_check = result[11] + result[12]
            minutes_check = result[14] + result[15]
            seconds_check = result[17] + result[18]
            current = datetime.datetime(int(year_check), int(month_check), int(date_check), int(hour_check),int(minutes_check), int(seconds_check))
            print(result)
            time.sleep(1)
            driver.refresh()
            Account(Account_Login_Record)
            Password(Password_Login_Record)
            ConfirmNumber()

        #Login
        driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click()  # 時間到了會自動幫你按登入
        print("LoginTime: "+result)
    except:
        driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click()  # 時間到了會自動幫你按登入
        print("已經嘗試登入")
    return

def RemoveCourse(OpenCode):
    global driver
    #Remove
    #要刪除的課程
    try:
        Remove_Number = driver.find_element("xpath","//*[@id=\"txtCosEleSeq\"]")
        Remove_Number.clear()
        Remove_Number.send_keys(OpenCode) #""不要刪掉
        driver.find_element("xpath","//*[@id=\"btnDel\"]").click()
    except:
        #messagebox.showinfo("提示","系統尚未開放，請耐心等學校開放")
        print("系統尚未開放，退選失敗")
    return
def AddCourse(OpenCode):
    global driver
    #Add
    RandomNumber = random.randrange(3)
    time.sleep(RandomNumber)
    #要加的課程
    try:
        Add_Number = driver.find_element("xpath","//*[@id=\"txtCosEleSeq\"]")
        Add_Number.clear()
        Add_Number.send_keys(OpenCode) #""不要刪掉
        driver.find_element("xpath","//*[@id=\"btnAdd\"]").click()
    except:
        #messagebox.showinfo("提示", "系統尚未開放，請耐心等學校開放")
        try:
            driver.find_element("xpath", "//*[@id=\"btnReLogin\"]").click()  # 按下重新登入
            Account(Account_Login_Record)
            Password(Password_Login_Record)
            ConfirmNumber()
            driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click()  #按下登入
        except:
            pass
    return

def ShowCurrentTable():
    global driver
    #Show the all Class that you have selected
    driver.find_element("xpath","//*[@id=\"btnEleCos\"]").click()
#============================================================================================
#main function
#messagebox.showinfo("提示",working_dir)
if __name__ == '__main__':
    OpenChrome()
    build_GUI()
```