https://github.com/yungwood/ical-filter-proxy
iCal proxy with support for user-defined filtering rules
https://github.com/yungwood/ical-filter-proxy
go ical icalendar
Last synced: 3 months ago
JSON representation
iCal proxy with support for user-defined filtering rules
- Host: GitHub
- URL: https://github.com/yungwood/ical-filter-proxy
- Owner: yungwood
- License: mit
- Created: 2024-07-31T11:41:03.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2026-03-08T01:53:01.000Z (3 months ago)
- Last Synced: 2026-03-08T07:07:22.947Z (3 months ago)
- Topics: go, ical, icalendar
- Language: Nix
- Homepage:
- Size: 91.8 KB
- Stars: 19
- Watchers: 2
- Forks: 6
- Open Issues: 19
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## What's this thing?
Do you have iCal feeds with a bunch of stuff you _don't_ need? Do you want to modify events generated by your rostering system?
iCal Filter Proxy is a simple service for proxying multiple iCal feeds while applying a list of filters to remove or modify events to suit your use case.
### Features
- Proxy multiple calendars
- Define a list of filters per calendar
- Match events using basic text and regex conditions
- Remove or modify events as they are proxied
### Built With
- Go
- [golang-ical](https://github.com/arran4/golang-ical)
- [yaml.v3](https://github.com/go-yaml/yaml/tree/v3.0.1)
- [DALL-E 2](https://openai.com/index/dall-e-2/) (app icon)
## Setup
### Docker
Docker images are published to [Docker Hub](https://hub.docker.com/r/yungwood/ical-filter-proxy). You'll need a config file (see below) mounted into the container at `/app/config.yaml`.
For example:
```bash
docker run -d \
--name=ical-filter-proxy \
-v config.yaml:/app/config.yaml \
-p 8080:8080/tcp \
--restart unless-stopped \
yungwood/ical-filter-proxy:latest
```
You can also adapt the included [`docker-compose.yaml`](./docker-compose.yaml) example.
### Kubernetes
You can deploy iCal Filter Proxy using the helm chart from [`yungwood/helm-charts/ical-filter-proxy`](https://github.com/yungwood/helm-charts/blob/main/charts/ical-filter-proxy).
```bash
helm repo add yungwood https://yungwood.github.io/helm-charts/
helm install --name your-release yungwood/ical-filter-proxy
```
### Build from source
You can also build the app and container from source.
```bash
# clone this repo
git clone git@github.com:yungwood/ical-filter-proxy.git
cd ical-filter-proxy
# build container image
docker build -t ical-filter-proxy:latest .
```
### Nix Flake
If you use Nix, you can build and run the application using the provided flake:
```bash
cd ical-filter-proxy
# build the application
nix build
# run the application
nix run . -- --help
# enter development shell with Go toolchain
nix develop
# run directly from GitHub
nix run github:yungwood/ical-filter-proxy -- --help
```
## Configuration
Calendars and filters are defined in a yaml config file. By default this is `config.yaml` (use the `-config` switch to change this). The configuration must define at least one calendar for ical-filter-proxy to start.
Example configuration (with comments):
```yaml
calendars:
# basic example
- name: example # used as slug in URL - e.g. ical-filter-proxy:8080/calendars/example/feed?token=changeme
publish_name: "My Calendar" # the published name of the calendar - uses upstream value if this line is skipped
token: "changeme" # optional - token must be used to pull iCal feed if defined
public: false # optional - must be true if token is blank or not defined
feed_url: "https://my-upstream-calendar.url/feed.ics" # URL for the upstream iCal feed
filters: # optional - if no filters defined the upstream calendar is proxied as parsed
- description: "Remove an event based on a regex"
remove: true # events matching this filter will be removed
match: # optional - all events will match if no rules defined
summary: # match on event summary (title)
contains: "deleteme" # must contain 'deleteme'
- description: "Remove descriptions from all events"
transform: # optional
description: # modify event description
remove: true # replace with a blank string
# example: removing noise from an Office 365 calendar
- name: outlook
token: "changeme"
feed_url: "https://outlook.office365.com/owa/calendar/.../reachcalendar.ics"
filters:
- description: "Remove canceled events" # canceled events remain with a 'Canceled:' prefix until removed
remove: true
match:
summary:
prefix: "Canceled: "
- description: "Remove events without descriptions"
remove: true
match:
description:
empty: true
- description: "Remove public holidays"
remove: true
match:
summary:
regex: ".*[Pp]ublic [Hh]oliday.*"
# example: cleaning up an OpsGenie feed
- name: opsgenie
token: "changeme"
feed_url: "https://company.app.opsgenie.com/webapi/webcal/getRecentSchedule?webcalToken=..."
filters:
- description: "Keep oncall schedule events and fix names"
match:
summary:
contains: "schedule: oncall"
stop: true # stops processing any more filters
transform:
summary:
replace: "On-Call" # replace the event summary (title)
- description: "Remove all other events"
remove: true
```
## Endpoints
The service exposes a simple HTTP API for accessing the proxied calendars.
The base URL is `http://:/calendars//feed`.
### Filters
Calendar events are filtered using a similar concept to email filtering. A list of filters is defined for each calendar in the config.
Each event parsed from `feed_url` is evaluated against the filters in sequence.
- All `match` rules for a filter must be true to match an event
- A filter with no `match` rules will _always_ match
- When a match is found:
- if `remove` is `true` the event is discarded
- `transform` rules are applied to the event
- if `stop` is `true` no more filters are processed
- If no match is found the event is retained by default
#### Match conditions
Each filter can specify match conditions against the following event properties:
- `summary` (string value)
- `location` (string value)
- `description` (string value)
- `url` (string value)
These match conditions are available for a string value:
- `empty` - if `true`, property must be absent or empty
- `contains` - property must contain this value
- `prefix` - property must start with this value
- `suffix` - property must end with this value
- `regex` - property must match the given regular expression (an invalid regex will result in no matches)
#### Transformations
Transformations can be applied to the following event properties:
- `summary` - string value
- `location` - string value
- `description` - string value
- `url` - string value
The following transformations are available for strings:
- `replace` - the property is replace with this value
- `remove` - if `true` the property is set to a blank string
### Secrets
You can load `feed_url` and `token` values from files by specifying the `feed_url_file` and `token_file` fields in the calendar configuration. When these fields are set, any values directly provided for `feed_url` or `token` are ignored.
For example:
```yaml
calendars:
- name: example
token_file: "/run/secrets/outlook-token"
feed_url_file: "/run/secrets/outlook-feed"
```
## Roadmap to 1.0
There are a few more features I would like to add before I call the project "stable" and release version 1.0.
- [ ] Time based event conditions
- [ ] Caching
- [ ] Prometheus metrics
- [ ] Testing
## Contributing
If you have a suggestion that would make this better, please feel free to open an issue or send a pull request.
## License
This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.
## Acknowledgments
This project was inspired by [darkphnx/ical-filter-proxy](https://github.com/darkphnx/ical-filter-proxy). I needed more flexibility with filtering rules and the ability to modify event descriptions... plus I wanted an excuse to finally write something in Go.