I small ical proxy to filter events based on simple rules - remove duplicate events (some start and end time) by selecting the one containing a special (configurable) text - remove all events that do not contain a specified text
  • Python 77.3%
  • HTML 22.3%
  • Dockerfile 0.4%
Find a file
joemat 6a0caab39f
Some checks failed
Build and push container image / build-and-push (push) Failing after 33s
.forgejo/workflows/build-container.yml aktualisiert
Replaced docker with podman
2026-07-13 07:39:14 +02:00
.forgejo/workflows .forgejo/workflows/build-container.yml aktualisiert 2026-07-13 07:39:14 +02:00
backend Refactoring, version 0.3 2026-06-28 17:39:14 +02:00
frontend Refactoring, version 0.3 2026-06-28 17:39:14 +02:00
nginx Refactoring, version 0.3 2026-06-28 17:39:14 +02:00
.gitignore Refactoring, version 0.3 2026-06-28 17:39:14 +02:00
Dockerfile Initial commit 2026-06-26 17:05:39 +02:00
LICENSE Added license 2026-06-28 17:52:37 +02:00
README.md Mentioned AI usage 2026-06-28 17:57:03 +02:00

iCal Filter Proxy

Small HTTP proxy that fetches remote iCalendar (.ics) feeds and applies simple deduplication / filtering rules before returning a new .ics feed.

This repository contains a compact Python backend and a tiny frontend helper for generating proxied calendar links.

Contents

  • backend/ - Python HTTP server and business logic
    • main.py - lightweight ThreadingHTTPServer that fetches remote .ics files and serves the filtered calendar
    • ical_logic.py - pure business logic for parsing, grouping and filtering iCalendar data (suitable for unit tests)
    • tests/ - unit tests for ical_logic.py (supports unittest; pytest tests are included as well)
  • frontend/ - a small static HTML page to generate proxy URLs
  • nginx/ - example nginx configuration with rate limiting, SSL and proxy settings
  • Dockerfile - container image definition

Quickstart (run locally)

  1. Start the server:
python3 backend/main.py

By default the server listens on port 8080. Change the port with the PROXY_PORT environment variable.

  1. Example request

Fetch and filter a remote calendar by passing the source URL as url and optional filters:

GET http://localhost:8080/?url=https://example.org/calendar.ics&required_text=MyTeam&priority_text=Official

Environment variables

  • PROXY_PORT (default: 8080) - server listen port
  • REQUIRED_TEXT - default required_text filter applied when not provided as query param
  • PRIORITY_TEXT - default priority_text filter applied when not provided as query param
  • PROXY_* (none used by backend) - example: Nginx can be used in front as reverse proxy

Security & operational notes

  • The backend strictly allows only http and https schemes to reduce SSRF risks.
  • Maximum download size is limited (MAX_FILE_SIZE in backend/main.py, default 10 MB) and enforced while streaming the response to avoid OOM.
  • A User-Agent header is sent when fetching external calendars; consider adjusting it to your needs.
  • Use an external reverse-proxy (example in nginx/nginx.conf) for TLS termination, rate-limiting and logging.

Tests

Run the included tests with the Python standard library's unittest discovery:

python3 -m unittest discover -s backend/tests -p 'test_*.py'

If you prefer pytest:

pip install pytest
python3 -m pytest backend/tests -q

Development notes

  • ical_logic.py is intentionally pure (no networking) and easy to unit-test. Use the functions in that module to expand parsing/filtering behavior.
  • If you want imports to behave as a package (e.g. from backend.ical_logic import process_ical), add an empty backend/__init__.py and adjust imports accordingly.

Docker

A Dockerfile is provided for packaging the service. Example build and run:

docker build -t ical-filter-proxy:latest .
docker run -p 8080:8080 --env PROXY_PORT=8080 ical-filter-proxy:latest

Contributing

Bug reports, tests and small improvements are welcome. Please open a pull request with a clear description of the change.

AI assistance

Some code refactorings, unit tests and documentation edits in this repository were produced with the assistance of an AI tool. All AI-generated outputs were reviewed, tested and adapted by the project maintainers. No sensitive prompts or private data are included in this repository.

License

This project is licensed under the GPLv3 License. See the LICENSE file for details.