2026-01-30 19:12:15 +01:00
# Anny Booking Automation
2025-07-28 10:42:47 +02:00
2026-01-30 19:12:15 +01:00
Automate study space reservations on [anny.eu ](https://anny.eu ) platforms used by university libraries. Logs in via SAML SSO, finds available slots, and books them automatically.
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
## Features
2025-08-02 22:37:17 +02:00
2026-02-06 18:45:56 +01:00
- **Pluggable SSO** - TUM, KIT provider included, easily extendable for other universities
2026-01-30 19:12:15 +01:00
- **Smart scheduling** - Waits until midnight when slots open, or runs immediately for testing
- **Configurable time slots** - Set your preferred booking times in order of priority
- **Automated execution** - Runs via GitHub Actions + cron-job.org for precise timing
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
## Quick Start
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
### 1. Clone and install
2025-08-02 22:37:17 +02:00
```bash
2026-01-30 19:12:15 +01:00
git clone https://github.com/wiestju/anny-booking-automation.git
2025-08-02 22:37:17 +02:00
cd anny-booking-automation
2026-01-30 19:12:15 +01:00
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
2025-08-02 22:37:17 +02:00
pip install -r requirements.txt
```
2026-01-30 19:12:15 +01:00
### 2. Configure credentials
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
Create a `.env` file:
2026-01-22 16:17:05 +01:00
2026-01-30 19:12:15 +01:00
```env
USERNAME=your_university_username
PASSWORD=your_university_password
2026-01-22 16:17:05 +01:00
```
2026-01-30 19:12:15 +01:00
### 3. Configure booking settings
2026-01-22 16:17:05 +01:00
2026-01-30 19:12:15 +01:00
Edit `config/constants.py` :
2026-01-22 16:17:05 +01:00
```python
2026-01-30 19:12:15 +01:00
SSO_PROVIDER = "kit" # Your university's SSO provider
RESOURCE_ID = None # Auto-detect, or set a specific resource ID
BOOKING_TIMES = [
{'start': '14:00:00', 'end': '19:00:00'}, # First priority
{'start': '09:00:00', 'end': '13:00:00'}, # Second priority
{'start': '20:00:00', 'end': '23:45:00'}, # Third priority
]
2026-01-22 16:17:05 +01:00
```
2026-01-30 19:12:15 +01:00
### 4. Run locally
2026-01-22 16:17:05 +01:00
2026-01-30 19:12:15 +01:00
```bash
python main.py
2026-01-22 16:17:05 +01:00
```
2026-01-30 19:12:15 +01:00
## Automated Scheduling
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
For daily automated bookings, use GitHub Actions triggered by [cron-job.org ](https://cron-job.org ).
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
### Why cron-job.org instead of GitHub's schedule?
2025-08-09 10:08:35 +02:00
2026-01-30 19:12:15 +01:00
GitHub Actions `on: schedule` has two issues:
- **Queue delays** - Workflows can be delayed by minutes, missing the booking window
- **UTC only** - No timezone support, requiring manual DST adjustments
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
cron-job.org provides precise, timezone-aware scheduling with no delays.
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
### Setup
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
#### 1. Add GitHub Secrets
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
In your repository: **Settings > Secrets and variables > Actions**
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
| Secret | Value |
|--------|-------|
| `USERNAME` | Your university username |
| `PASSWORD` | Your university password |
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
#### 2. Create a GitHub Personal Access Token
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
1. Go to [GitHub Settings > Developer settings > Personal access tokens ](https://github.com/settings/tokens )
2. Generate a token with `repo` scope (or fine-grained with Actions read/write)
3. Copy the token
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
#### 3. Configure cron-job.org
2025-08-09 10:08:35 +02:00
2026-01-30 19:12:15 +01:00
Create a new cron job with these settings:
2025-08-09 10:08:35 +02:00
2026-01-30 19:12:15 +01:00
| Setting | Value |
|---------|-------|
| URL | `https://api.github.com/repos/YOUR_USERNAME/anny-booking-automation/actions/workflows/schedule.yml/dispatches` |
| Schedule | `58 23 * * *` (23:58 daily) |
| Timezone | `Europe/Berlin` (or your timezone) |
| Request method | `POST` |
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
**Headers:**
2025-08-02 22:37:17 +02:00
```
2026-01-30 19:12:15 +01:00
Authorization: Bearer YOUR_GITHUB_TOKEN
Content-Type: application/json
Accept: application/vnd.github.v3+json
2025-08-02 22:37:17 +02:00
```
2026-01-30 19:12:15 +01:00
**Request body:**
2025-08-02 22:37:17 +02:00
```json
{"ref": "main"}
```
2026-01-30 19:12:15 +01:00
### How it works
1. cron-job.org triggers the workflow at **23:58**
2. The script logs in and establishes a session
3. It waits until **00:00** when new slots become available
4. Instantly books the first available slot from your priority list
## Project Structure
2025-08-02 22:37:17 +02:00
```
2026-01-30 19:12:15 +01:00
anny-booking-automation/
├── main.py # Entry point
├── config/
│ └── constants.py # URLs, timezone, booking times
├── auth/
│ ├── session.py # Login session handling
│ └── providers/ # SSO provider implementations
│ ├── base.py # Abstract base class
│ └── kit.py # KIT provider
├── booking/
│ └── client.py # Booking API client
└── utils/
└── helpers.py # Utility functions
2025-08-02 22:37:17 +02:00
```
2026-01-30 19:12:15 +01:00
## Adding a New SSO Provider
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
Create `auth/providers/youruni.py` :
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
```python
from auth.providers.base import SSOProvider
class YourUniProvider(SSOProvider):
name = "youruni"
domain = "youruni.edu"
def authenticate(self) -> str:
# Implement SAML authentication flow
# Use self.session, self.redirect_response, self.username, self.password
# Return HTML containing SAMLResponse
pass
```
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
Register in `auth/providers/__init__.py` :
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
```python
from auth.providers.youruni import YourUniProvider
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
PROVIDERS = {
"kit": KITProvider,
"youruni": YourUniProvider,
}
```
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
## License
2025-08-02 22:37:17 +02:00
2026-01-30 19:12:15 +01:00
MIT