Skip to content

Instantly share code, notes, and snippets.

@DeflateAwning
Last active May 2, 2018 16:07
Show Gist options
  • Save DeflateAwning/5878a699af8477806891d9971e918666 to your computer and use it in GitHub Desktop.
Save DeflateAwning/5878a699af8477806891d9971e918666 to your computer and use it in GitHub Desktop.
Tool for watching class availability for non-waitlistable UCalgary classes
#!/usr/bin/env python3
import urllib.request
import xml.etree.ElementTree as ET
import time, random, math
import smtplib
from email.message import EmailMessage
# from IPython import embed # for debugging, requires pip install
# Configuration: Email Login
fromEmail = "ucalgary.class.notifier@mail.com"
fromEmailPassword = "asdfASDF1234"
# Configuration: Email Sending
watchList = {"2018 Spring|MATH 375":["<your email>"], "2018 Spring|ENCM 339":["<your email>"]}
# General Constant Declaration
semesterList = {"2018 Spring":"32183", "2018 Summer":"32185", "2018 Fall":"32187", "2019 Winter":"32191"}
requestString = "https://vsb.my.ucalgary.ca/getclassdata.jsp?term=%TermNumber%&course_0_0=%CourseName%&rq_0_0=null&t=%tCode%&e=%eCode%&nouser=1&_=%dateCode%"
def getOpenSpots(course):
# Generate stupid request data to please server
dateCode = str(int(time.time())) + str(random.randint(111, 999)) # get time since epoch, in ms (add the ms component to seconds randomly)
tCode = (math.floor((int(dateCode)) / 60000)) % 1000
eCode = tCode%3 + tCode%29 + tCode%42
thisSemester = course.split("|")[0]
thisCourse = course.split("|")[1]
response = urllib.request.urlopen(requestString.replace("%TermNumber%", semesterList[thisSemester]).replace("%CourseName%", thisCourse.replace(" ", "-")).replace("%tCode%", str(tCode)).replace("%eCode%", str(eCode)).replace("%dateCode%", dateCode)).read()
root = ET.fromstring(response)
#print(response)
if "Check your PC" in str(response):
# An error has occured, return false and print an error
print("PC time error.")
return False
OSReport = {} # example: {'LEC': 0, 'TUT': 0, 'LAB': 0}
for block in root.iter("block"):
# each block is a TUT0x or LEC0x or other entry
disp = block.attrib["disp"] # TUT 01
os = int(block.attrib["os"]) # number of open spots in TUT 01
typeof = block.attrib["type"] # TUT or LEC or LAB
#print(os)
if typeof not in OSReport:
OSReport[typeof] = os
else:
OSReport[typeof] += os
return OSReport
def sendNotificationEmail(toAddress, courseName, OSReport):
totalOS = sum([OSReport[i] for i in OSReport])
detailsBreakdown = "\r\n".join(["\t- " + i + ": " + str(OSReport[i]) + " Open Spots" for i in OSReport])
message = """
courseName has totalOS open spots (including labs, lectures, and tutorials)! Sign up immediately on http://my.ucalgary.ca or with the UCalgary Schedule Builder (https://vsb.my.ucalgary.ca/login.jsp) to get a spot in courseName.
Open spots in each course component:
detailsBreakdown""".replace("courseName", courseName).replace("totalOS", str(totalOS)).replace("detailsBreakdown", detailsBreakdown)
body = "\r\n".join(["To: " + toAddress, "From: " + fromEmail, "Subject: Class Availability Notifier: " + courseName + " has an open spot!", '', message])
server = smtplib.SMTP("smtp.mail.com", 587) # Port: 587
server.ehlo()
server.starttls()
server.login(fromEmail, fromEmailPassword)
try:
server.sendmail(fromEmail, [toAddress], body)
print("Message successfully sent to " + toAddress + " for spot in " + courseName)
except:
print("Error: Message not sent to " + toAddress + " for spot in " + courseName)
server.quit()
#sendNotificationEmail(fromEmail, "Math 200", {'LEC': 1, 'TUT': 1, 'LAB': 2}) # Sample Run for Testing Mailer
#sendNotificationEmail(fromEmail, "Math 200", {}) # Sample Run for Testing Mailer
while 1:
for course in watchList:
courseOSReport = getOpenSpots(course)
totalOS = sum([courseOSReport[i] for i in courseOSReport]) # Current used metric
minOS = min([courseOSReport[i] for i in courseOSReport]) # Really the useful one because you need all course components
if totalOS > 0:
for toAddress in watchList[course]:
sendNotificationEmail(toAddress, course, courseOSReport)
print(course, str(courseOSReport))
#print(courseOSReport)
time.sleep(1)
time.sleep(6)
# embed() # Debug Console
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment