{"id":39789070,"url":"https://github.com/dchaib/pronote2calendar","last_synced_at":"2026-01-18T12:13:37.732Z","repository":{"id":318834289,"uuid":"1065869951","full_name":"dchaib/pronote2calendar","owner":"dchaib","description":"A simple tool to export your Pronote timetable to Google Calendar for easy access and integration with other apps.","archived":false,"fork":false,"pushed_at":"2026-01-14T00:38:28.000Z","size":248,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-14T04:25:09.166Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dchaib.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-28T15:39:05.000Z","updated_at":"2025-12-23T16:59:16.000Z","dependencies_parsed_at":"2026-01-14T03:00:33.921Z","dependency_job_id":null,"html_url":"https://github.com/dchaib/pronote2calendar","commit_stats":null,"previous_names":["dchaib/pronote2calendar"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/dchaib/pronote2calendar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchaib%2Fpronote2calendar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchaib%2Fpronote2calendar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchaib%2Fpronote2calendar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchaib%2Fpronote2calendar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dchaib","download_url":"https://codeload.github.com/dchaib/pronote2calendar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchaib%2Fpronote2calendar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28535533,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T10:13:46.436Z","status":"ssl_error","status_checked_at":"2026-01-18T10:13:11.045Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-18T12:13:37.614Z","updated_at":"2026-01-18T12:13:37.699Z","avatar_url":"https://github.com/dchaib.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pronote2Calendar\n\n**Pronote2Calendar** exports your **Pronote** timetable to **Google Calendar** so you can easily access it and integrate it with other applications.\n\n## Features\n\n- **Sync your Pronote timetable**: Export your Pronote school timetable to a Google Calendar.\n- **Supports Pronote accounts**: Works with both **parent** and **child** accounts.\n- **Configurable sync period**: Specify the number of days (from today) to sync.\n- **Automated \u0026 Ephemeral**: Designed to run, sync, and stop. Best suited for running on a schedule (e.g., via cron).\n\n## Prerequisites\n\nTo use **Pronote2Calendar**, you will need the following:\n\n- A **Pronote account** (parent or child).\n- A **Google Service account** with calendar access.\n\n### Pronote account\n\nTo interact with your Pronote account, you need to set up credentials. Use the `init` command provided in the Docker image to generate the necessary configuration file.\n\nUsing the QR code login method (recommended):\n\n1. Log in to your Pronote account.\n2. Generate the QR code. Note the PIN you entered.\n\n    ![Pronote header](doc/images/pronote-header.png)\n\n3. Read the QR code with any QR code reader app. You should get a JSON object like this:\n\n    ```json\n    {\"avecPageConnexion\":false,\"jeton\":\"13895...AAB\",\"login\":\"477...65\",\"url\":\"https://\u003cschool_id\u003e.index-education.net/pronote/...\"}\n    ```\n\n4. Run the `init` command from the Docker image to generate credentials:\n\n    ```bash\n    docker run --rm -it ghcr.io/dchaib/pronote2calendar:latest init --qr_code '\u003cyour QR code\u003e' --pin \u003cyour PIN\u003e\n    ```\n\n5. Copy the credentials from the output to a file named `credentials-pronote.json`. Example structure:\n\n    ```json\n    {\n        \"pronote_url\": \"https://\u003cschool_id\u003e.index-education.net/pronote/...\",\n        \"username\": \"xxxxxxxxxx\",\n        \"password\": \"627AE53B...\",\n        \"client_identifier\": \"45A64E1...\",\n        \"uuid\": \"0cb7f2459...\"\n    }\n    ```\n\nYou can also use your username and password (if you have one). Simply run the `init` command without arguments and follow the instructions:\n```bash\ndocker run --rm -it ghcr.io/dchaib/pronote2calendar:latest init\n```\n\n### Google service account\n\nTo modify your Google Calendar, you need a Google service account and a service account key (JSON).\n\n1. Create a Google Cloud project (if you don't have one): https://developers.google.com/workspace/guides/create-project\n2. Enable the Google Calendar API: https://console.cloud.google.com/apis/library/calendar-json.googleapis.com\n3. Create a service account: https://developers.google.com/workspace/guides/create-credentials#create_a_service_account\n4. Create and download a service account key in JSON format: https://developers.google.com/workspace/guides/create-credentials#create_credentials_for_a_service_account\n5. Save the downloaded JSON as `credentials-google.json`.\n6. Share the Google Calendar you want to use with the service account and grant the permission \"Make changes to events\".\n\n\n## Setup\n\n### 1. Configuration File (`config.yaml`)\n\nCreate a `config.yaml` file in the root of your project directory. Here's an example with a `child` account:\n\n```yaml\npronote:\n  connection_type: token\n  account_type: child\ngoogle_calendar:\n  calendar_id: \"xxx@gmail.com\"\nsync:\n  weeks: 3\n```\n\nHere is an example with a `parent` account:\n```yaml\npronote:\n  connection_type: token\n  account_type: parent\n  child: \u003cchild_name\u003e\ngoogle_calendar:\n  calendar_id: \"xxx@gmail.com\"\nsync:\n  weeks: 3\n```\n\n* **pronote**\n  - **connection_type**: Defines how you connect to Pronote. There are 2 options, depending on what you used to generate the credentials:\n    - `token` if you used the QR code,\n    - `password` if you used your username and password.\n\n    This is optional, the default value is `token`.\n  - **account_type**: Can be either `parent` or `child` depending on the account you used. This is optional, the default value is `child`.\n  - **child**: Only needed if using a `parent` account; specify the name of your child as shown in Pronote.\n* **google_calendar**\n  - **calendar_id**: The **ID** of your Google Calendar (can be found in Google Calendar settings).\n* **sync**\n  - **weeks**: The number of weeks (including the current one) to sync. Example: If set to `3`, it will sync the current week and the next 2 weeks. This parameter is optional. If not specified, the default value is `3`. The minimum is `1`.\n\n#### Optional: Time Adjustments\n\nYou can adjust lesson times for specific weekdays and time slots. This is useful if Pronote displays different times than the actual class times. Use the `time_adjustments` field:\n\n```yaml\npronote: { ... }\ngoogle_calendar: { ... }\nsync: { ... }\nadjustments:\n  time:\n    - weekdays: [ 1, 2, 4, 5 ]\n      start_times:\n        \"08:00\": \"08:05\"\n        \"09:00\": \"09:05\"\n      end_times:\n        \"14:40\": \"14:45\"\n    - weekdays: [ 3 ]\n      start_times:\n        \"9:00\": \"8:55\"\n```\n\n* **adjustments.time**: An array of adjustment rules. Each rule applies to specific weekdays and adjusts lesson times. This parameter is optional; if not specified, no time adjustments are applied.\n  - **weekdays**: An array of weekday numbers (ISO format: 1=Monday, 2=Tuesday, ..., 7=Sunday) to which this rule applies.\n  - **start_times**: A mapping of original start times (in `HH:MM` format) to adjusted start times. Only lessons matching the original time will be adjusted.\n  - **end_times**: A mapping of original end times (in `HH:MM` format) to adjusted end times. Only lessons matching the original time will be adjusted.\n\nFor example, the first rule above adjusts all lessons on Monday, Tuesday, Thursday, and Friday (weekdays 1, 2, 4, 5) that start at 08:00 to start at 8:05 instead. The second rule adjusts Wednesday lessons (weekday 3) that start at 09:00 to start at 8:55.\n\n#### Optional: Subject Adjustments\n\nYou can adjust lesson subject names to display more user-friendly versions. This is useful if Pronote displays long or technical subject names that you prefer to shorten. Use the `subject` field under `adjustments`:\n\n```yaml\npronote: { ... }\ngoogle_calendar: { ... }\nsync: { ... }\nadjustments:\n  subject:\n    \"Sciences de la Vie et de la Terre\": \"SVT\"\n    \"Histoire-Géographie\": \"Histoire-Géo\"\n    \"Éducation musicale\": \"Musique\"\n    \"Éducation physique et sportive\": \"EPS\"\n```\n\n* **adjustments.subject**: A mapping of original subject names to adjusted subject names. This parameter is optional; if not specified, no subject adjustments are applied.\n  - Each key is the original subject name as displayed in Pronote.\n  - Each value is the adjusted subject name that will be displayed in Google Calendar.\n\nFor example, the mapping above will replace \"Sciences de la Vie et de la Terre\" with \"SVT\" for all lessons with that subject. Any subject not in the mapping will remain unchanged.\n\n#### Optional: Event Templates\n\nYou can customize how lesson events appear in Google Calendar by defining templates for the event summary, description, and location. This uses [Jinja2 templating](https://jinja.palletsprojects.com/) to dynamically generate event properties based on lesson data. Use the `templates` field under `events`:\n\n```yaml\npronote: { ... }\ngoogle_calendar: { ... }\nsync: { ... }\nadjustments: { ... }\nevents:\n  templates:\n    summary: \"{{ subject }}\"\n    description: \"{{ teacher_name }}\"\n    location: \"{{ classroom }}\"\n```\n\n##### Customizable Properties\n\nThe following properties can be customized:\n\n* **summary**: The title of the calendar event. Default: `\"{{ subject }}\"`\n* **description**: The description of the event. **Supports HTML formatting** for rich text. Default: `\"{{ teacher_name }}\"`\n* **location**: The location field of the event. Default: `\"{{ classroom }}\"`\n\nAll three properties are optional. If not specified, the default values shown above are used.\n\n##### Available Variables\n\nYou can use any of the following variables in your templates:\n\n* **Lesson Details**\n  - `start` - Starting time of the lesson (datetime)\n  - `end` - Ending time of the lesson (datetime)\n  - `subject` - Subject name (string, empty if not available)\n  - `in_groups` - Whether the subject is in groups (boolean)\n  - `memo` - Lesson memo/notes (string, empty if not available)\n  - `status` - Status of the lesson (string, empty if not available)\n  - `background_color` - Background color of the lesson (string, empty if not available)\n\n* **Teacher Information**\n  - `teacher_name` - Name of the teacher (string, empty if not available)\n  - `teacher_names` - List of teacher names (list of strings, empty if not available)\n\n* **Location Information**\n  - `classroom` - Name of the classroom (string, empty if not available)\n  - `classrooms` - List of classroom names (list of strings, empty if not available)\n  - `virtual_classrooms` - List of URLs for virtual classrooms (list of strings)\n\n* **Group Information**\n  - `group_name` - Name of the group (string, empty if not available)\n  - `group_names` - List of group names (list of strings, empty if not available)\n\n* **Lesson Status Flags**\n  - `canceled` - Whether the lesson is canceled (boolean)\n  - `outing` - Whether it is a pedagogical outing (boolean)\n  - `exempted` - Whether the student is presence is exempt (boolean)\n  - `detention` - Whether it is marked as detention (boolean)\n  - `test` - Whether there will be a test in the lesson (boolean)\n  - `normal` - Whether the lesson is considered normal (not detention or outing) (boolean)\n\n##### Examples\n\nHere are some practical examples of template customization:\n\n```yaml\nevents:\n  templates:\n    # Include subject and teacher\n    summary: \"{{ subject }} - {{ teacher_name }}\"\n    \n    # Include both classroom and group information\n    description: \"Room: {{ classroom }}\\nGroup: {{ group_name }}\"\n    \n    # Use HTML formatting for rich text\n    description: \"\u003cb\u003e{{ subject }}\u003c/b\u003e\u003cbr\u003eTeacher: {{ teacher_name }}\u003cbr\u003eRoom: {{ classroom }}\"\n    \n    # Show time details\n    summary: \"[{{ start.strftime('%H:%M') }}] {{ subject }}\"\n    \n    # Conditional example (using Jinja2 filters)\n    description: \"{% if teacher_name %}Teacher: {{ teacher_name }}{% endif %}\"\n```\n\n### 2. Create your Docker Compose file\n\nYou can use **Docker Compose** to run the container. Here is an example:\n\n```yaml\nservices:\n  pronote2calendar:\n    image: \"ghcr.io/dchaib/pronote2calendar:latest\"\n    volumes:\n      - \"./config.yaml:/app/config.yaml:ro\"\n      - \"./credentials-google.json:/app/credentials-google.json:ro\"\n      - \"./credentials-pronote.json:/app/credentials-pronote.json:rw\"\n```\n\nIf you are using the QR code login method, the Pronote credentials file needs write permissions (`rw`) because the password is updated after each login. Otherwise, you can keep it read-only (`ro`).\n\nTo keep the example simple, it uses the `latest` tag. For reproducibility, you should pin a specific tagged image in production.\n\nIt also assumes that all the configuration files (`config.yaml`, `credentials-google.json`, and `credentials-pronote.json`) are in the same directory as your compose file.\n\n\n## Running the App\n\nAfter setting everything up, you can run the container using Docker Compose. Since the container is ephemeral, it will run, sync your calendar, and then stop automatically.\n\nIf all goes well, you should see the logs similar to those:\n```\n2025-10-25T18:31:51+0200 INFO pronote2calendar: Updating lessons from 2025-10-25T00:00:00+02:00 to 2025-11-14T00:00:00+02:00\n2025-10-25T18:31:51+0200 INFO pronote2calendar: Initializing Pronote client\n2025-10-25T18:31:51+0200 INFO pronotepy.pronoteAPI: INIT\n2025-10-25T18:31:51+0200 INFO pronotepy.pronoteAPI: successfully logged in as xxxxxxxxxx\n2025-10-25T18:31:51+0200 INFO pronotepy.pronoteAPI: got onglets data.\n2025-10-25T18:31:51+0200 INFO pronote2calendar: Fetching lessons from Pronote\n2025-10-25T18:31:51+0200 INFO pronote2calendar: Fetched 38 lessons\n2025-10-25T18:31:51+0200 INFO pronote2calendar: Initializing Google Calendar client\n2025-10-25T18:31:51+0200 INFO googleapiclient.discovery_cache: file_cache is only supported with oauth2client\u003c4.0.0\n2025-10-25T18:31:51+0200 INFO pronote2calendar: Fetching events from Google Calendar\n2025-10-25T18:31:52+0200 INFO pronote2calendar: Fetched 30 existing events\n2025-10-25T18:31:52+0200 INFO pronote2calendar: Detecting changes between lessons and calendar events\n2025-10-25T18:31:52+0200 INFO pronote2calendar: Change detection produced add=8 remove=0 update=0\n2025-10-25T18:31:52+0200 INFO pronote2calendar: Applying changes to calendar\n2025-10-25T18:32:08+0200 INFO pronote2calendar: Finished applying changes\n```\n\n### Recommended: Schedule Regular Syncs\n\nIf you want to sync regularly (and you most likely do), it is best to run it on a schedule (e.g., using `cron`) to sync your timetable at regular intervals, without overwhelming the Pronote servers. For example, running it daily would be a good starting point:\n\n```bash\n0 0 * * * cd /path/to/compose/file \u0026\u0026 docker compose up -d\n```\n\nThis would run the synchronization at midnight every day.\n\n\n## Troubleshooting\n\n### Common Issues\n\n* **Pronote Login Issues**: If you're unable to log in, ensure that your `credentials-pronote.json` file is properly generated by running the `init` command. If you used the QR code, the file needs write permissions for the app to update the password after each login.\n* **Google Calendar Permissions**: Make sure your Google Service account has proper permissions to make changes to events.\n\n## Contributing\n\nFeel free to ask questions, submit issues and propose improvements. Contributions are welcome!\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdchaib%2Fpronote2calendar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdchaib%2Fpronote2calendar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdchaib%2Fpronote2calendar/lists"}