Skip to content

Instantly share code, notes, and snippets.

@martenlienen
Last active June 24, 2021 21:20
Show Gist options
  • Save martenlienen/0fa30800c14c03478eb1d919688bfbd3 to your computer and use it in GitHub Desktop.
Save martenlienen/0fa30800c14c03478eb1d919688bfbd3 to your computer and use it in GitHub Desktop.
Extract CF Munich's schedule from their website into an excel sheet. The userscript extracts the data from their eversports widget into JSON and the python script formats that data into an excel sheet.
#!/usr/bin/env python
import argparse
import json
from pathlib import Path
from openpyxl import Workbook
from openpyxl.styles import Alignment, Font
WEEKDAYS = [
"Montag",
"Dienstag",
"Mittwoch",
"Donnerstag",
"Freitag",
"Samstag",
"Sonntag",
]
def minutes_to_time(minutes):
hours = minutes // 60
mins = minutes % 60
return f"{hours:02d}:{mins:02d}"
def class_category(class_):
name = class_["name"].lower()
if "bodybuilding" in name:
return "Functional Bodybuilding"
elif "kids" in name:
return "CrossFit Kids"
elif "crossfit" in name:
return "CrossFit"
elif "gymnastics" in name:
return "Gymnastics"
elif "open" in name:
return "Open Gym"
elif "olympic" in name:
return "Weightlifting"
elif "strongman" in name:
return "Strongman"
elif "hyrox" in name:
return "Hyrox"
elif "mobility" in name:
return "Mobility"
elif "yoga" in name:
return "Yoga"
elif "endurance" in name:
if "advanced" in name:
return "Endurance Advanced"
else:
return "Endurance"
elif "rookie" in name:
return "Rookie"
else:
return name
def main():
parser = argparse.ArgumentParser()
parser.add_argument("schedule", help="Exported JSON schedule")
parser.add_argument("sheet", help="Schedule excel sheet")
args = parser.parse_args()
schedule_path = Path(args.schedule)
sheet_path = Path(args.sheet)
schedule_data = json.loads(schedule_path.read_text())
processed = [
{
start: sorted(list(set(class_category(cls) for cls in classes)))
for start, classes in day.items()
}
for day in schedule_data
]
earliest_time = min(min(map(int, day.keys())) for day in schedule_data)
latest_time = max(max(map(int, day.keys())) for day in schedule_data)
wb = Workbook()
ws = wb.active
ws.title = "CFM Schedule"
for time_idx, start in enumerate(range(earliest_time, latest_time + 1, 30)):
ws.cell(2 + time_idx, 1, minutes_to_time(start))
start_col = 2
for day_idx, day in enumerate(processed):
weekday = WEEKDAYS[day_idx]
max_parallel_slots = max(len(v) for v in day.values())
end_col = start_col + max_parallel_slots - 1
cell = ws.cell(1, start_col)
cell.value = weekday
cell.font = cell.font + Font(bold=True)
cell.alignment = cell.alignment + Alignment(horizontal="center")
ws.merge_cells(
start_row=1, end_row=1, start_column=start_col, end_column=end_col
)
for start, classes in day.items():
row = (int(start) - earliest_time) // 30 + 2
for cls_idx, name in enumerate(classes):
ws.cell(row, start_col + cls_idx, name)
start_col = end_col + 1
wb.save(sheet_path)
if __name__ == "__main__":
main()
// ==UserScript==
// @name CFM schedule extract
// @version 1
// @include https://www.eversports.de/widget/w/A9ATBg
// @grant none
// ==/UserScript==
(function() {
"use strict";
let schedule_root = document.querySelector(".calendar");
let rows = schedule_root.querySelectorAll(".row.calendar__container");
let schedule = [{}, {}, {}, {}, {}, {}, {}];
for (const row of Array.from(rows)) {
let days = row.querySelectorAll(".calendar__day");
for (const [index, day] of Array.from(days).entries()) {
let slots = day.querySelectorAll(".calendar__slot");
for (const slot of Array.from(slots)) {
let name = slot.querySelector(".session-name").textContent;
let [start, duration] = slot.querySelector(".session-time").textContent.split(" ● ");
let [hour, min] = start.split(":");
start = 60 * parseInt(hour) + parseInt(min);
duration = parseInt(duration.split(" ")[0]);
if (!schedule[index].hasOwnProperty(start)) {
schedule[index][start] = [];
}
schedule[index][start].push({name, start, duration});
}
}
}
console.log(JSON.stringify(schedule));
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment