---
title: CalendarChanger
subtitle: Smart ICS Proxy for Structured and Customizable Calendars
showOnCv: true
type: Personal
abstract: Self-hosted ICS proxy that makes university calendar feeds usable in a normal calendar app, moving event details into the fields clients actually read and splitting lectures, exams and practicals into separate subscriptions. Built in ASP.NET Core, containerized with Docker and deployed with Ansible.

content:
  - src: cover
    srcDark: cover-dark
    filetype: .webp
  - src: calendar
    srcDark: calendar-dark
    filetype: .webp

pdfFiles: []

quickLinks:
  - kind: github
    url: https://github.com/wtb04/calendarchanger
  - kind: demo
    url: https://calendarchanger.w-tb.nl

keywords: []
supervisors: []

keyFeatures:
  - "ICS Proxy: Rewrites feeds to use correct iCalendar fields instead of description text"
  - "Smart Grouping: Creates separate subscriptions for lectures exams and practicals"
  - "Web Interface: Edit or hide events without altering the source feed"
  - "Event Hashing: Restores edited events automatically when the source changes"
  - "Location Integration: Adds Apple Maps and Mazemap links for classroom details"
  - "RFC 2445 Compliance: Outputs standards-compliant ICS data"
  - "Continuous Sync: Periodically refreshes from the source feed"
  - "Dockerized Deployment: Automated through Ansible for continuous delivery"

tags:
  - Backend
  - Automation
  - ASP.Net Core
  - Docker
  - Web
  - Frontend

---

CalendarChanger is a self-hosted <a href='https://www.rfc-editor.org/rfc/rfc2445' target='_blank'>iCalendar (ICS)</a> proxy that fixes and enriches exported calendar feeds. The project began when the University of Twente adopted <a href='https://www.timeedit.net/nl_utwente' target='_blank'>TimeEdit</a> in 2024. While TimeEdit provided technically valid ICS files, it stored all details inside the description field instead of using the correct iCalendar fields such as LOCATION and ATTENDEE. This made the data unreadable in most calendar apps. CalendarChanger acts as a middle layer between TimeEdit and the calendar client, extracting the event data and putting it back into the fields the standard actually has for it. It cleans titles, assigns teachers as attendees and separates lectures, exams and practicals into individual feeds so users can color-code them in their calendar. 

It also adds location detail, inserting Apple Maps locations and linking building names to a custom Mazemap redirect endpoint that resolves rooms to <a href='https://use.mazemap.com/' target='_blank'>Mazemap</a> locations. The system runs continuously, fetching updates from the original feed and serving always up-to-date subscriptions. 

The web interface lets users hide or modify events such as cancelled classes or changed times even though the source is read-only. Each event is hashed by its contents so when TimeEdit changes an event it goes back to the source version. The backend is built with ASP.NET Core and Razor Pages, containerized with Docker and deployed automatically with Ansible to a private cloud server.