bring in code made by che

This commit is contained in:
Ugric
2026-01-23 01:39:54 +00:00
parent d961d1f80c
commit ecd728fe27
17 changed files with 187 additions and 32 deletions

73
main.py
View File

@@ -3,6 +3,9 @@ from datetime import datetime, timezone
import pytz
import hashlib
import os
from flask import Flask, request, send_file, render_template
import requests
from requests_ntlm import HttpNtlmAuth
# ------------------------------------------------------------
# Config
@@ -12,15 +15,12 @@ RESPONSE_FILE = "response.txt"
OLD_CALENDAR = "old_calendar.ics"
NEW_CALENDAR = "calendar.ics"
LOCAL_TZ = pytz.timezone("Europe/London")
URL = "https://webapp.coventry.ac.uk/Timetable-main/Timetable/Current"
# ------------------------------------------------------------
# Parsing timetable JS
# ------------------------------------------------------------
app = Flask(__name__)
def parse_events(events_data):
# Replace JS date objects
events_data = events_data.replace("new Date", "")
cleaned_data = ""
for line in events_data.split("\n"):
@@ -67,9 +67,6 @@ def get_events_data_from_file(path):
return source.split("events:")[1].split("]")[0] + "]"
# ------------------------------------------------------------
# ICS helpers
# ------------------------------------------------------------
def ics_time(dt):
return dt.astimezone(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
@@ -89,13 +86,9 @@ def create_ics_event(event):
"end": event["end"],
}
# ------------------------------------------------------------
# Load existing calendar (UIDs only)
# ------------------------------------------------------------
def load_existing_uids(path):
uids = set()
if not os.path.exists(path):
return uids
@@ -109,31 +102,30 @@ def load_existing_uids(path):
if line == "BEGIN:VEVENT":
current_uid = None
cancelled = False
elif line.startswith("UID:"):
current_uid = line[4:]
elif line == "STATUS:CANCELLED":
cancelled = True
elif line == "END:VEVENT" and current_uid and not cancelled:
uids.add(current_uid)
return uids
# ------------------------------------------------------------
# Main
# ------------------------------------------------------------
def fetch_timetable(username, password):
session = requests.Session()
session.auth = HttpNtlmAuth(username, password)
def main():
r = session.get(URL)
r.raise_for_status()
with open("response.txt", "w", encoding="utf-8") as f:
f.write(r.text)
def build_calendar():
events_js = get_events_data_from_file(RESPONSE_FILE)
parsed_events = parse_events(events_js)
new_events = [
create_ics_event(e)
for e in parsed_events
if e
]
new_events = [create_ics_event(e) for e in parsed_events if e]
old_uids = load_existing_uids(OLD_CALENDAR)
new_uids = {e["uid"] for e in new_events}
@@ -147,7 +139,6 @@ def main():
"CALSCALE:GREGORIAN",
]
# Add / update events
for ev in new_events:
lines.extend([
"BEGIN:VEVENT",
@@ -160,7 +151,6 @@ def main():
"END:VEVENT",
])
# Cancel removed events
for uid in old_uids - new_uids:
lines.extend([
"BEGIN:VEVENT",
@@ -174,12 +164,31 @@ def main():
with open(NEW_CALENDAR, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
print(f"Added / updated: {len(new_events)}")
print(f"Removed: {len(old_uids - new_uids)}")
print(f"Wrote {NEW_CALENDAR}")
# ------------------------------------------------------------
# Flask
# ------------------------------------------------------------
@app.route("/")
def index():
return render_template("index.html")
@app.route("/login-and-download", methods=["POST"])
def login_and_download():
data = request.get_json()
username = data["username"]
password = data["password"]
username = f'COVENTRY\\{username}'
try:
fetch_timetable(username, password) #request
build_calendar()
return send_file(
NEW_CALENDAR,
as_attachment=True,
download_name="timetable.ics",
mimetype="text/calendar"
)
except Exception as e:
return str(e), 400
if __name__ == "__main__":
main()
app.run(debug=True)