{"id":23750615,"url":"https://github.com/avkrapivin/telegram-calendar","last_synced_at":"2026-04-08T18:31:13.822Z","repository":{"id":268607739,"uuid":"904909460","full_name":"avkrapivin/telegram-calendar","owner":"avkrapivin","description":"Telegram bot for creating events in Google calendar.","archived":false,"fork":false,"pushed_at":"2025-01-26T21:33:47.000Z","size":100,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-01T08:29:17.957Z","etag":null,"topics":["assembly-ai","aws","caffeine","google-calendar-api","java","json","lombok","openai-api","postgresql","spring","telegram-bot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/avkrapivin.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}},"created_at":"2024-12-17T19:32:45.000Z","updated_at":"2025-01-26T21:33:50.000Z","dependencies_parsed_at":"2025-01-25T13:27:38.323Z","dependency_job_id":"e9af1dbf-823f-4dd3-b28e-c15e890ff5a3","html_url":"https://github.com/avkrapivin/telegram-calendar","commit_stats":null,"previous_names":["avkrapivin/telegram-calendar"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/avkrapivin/telegram-calendar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avkrapivin%2Ftelegram-calendar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avkrapivin%2Ftelegram-calendar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avkrapivin%2Ftelegram-calendar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avkrapivin%2Ftelegram-calendar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/avkrapivin","download_url":"https://codeload.github.com/avkrapivin/telegram-calendar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/avkrapivin%2Ftelegram-calendar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31568576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["assembly-ai","aws","caffeine","google-calendar-api","java","json","lombok","openai-api","postgresql","spring","telegram-bot"],"created_at":"2024-12-31T16:23:20.201Z","updated_at":"2026-04-08T18:31:13.784Z","avatar_url":"https://github.com/avkrapivin.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Telegram bot Calendar\n\n## Description\n\nTelegram bot for managing Google Calendar through Telegram. The bot allows:\n\n- **Event creation** via text and voice messages with automatic natural language recognition\n- **Event search** in the calendar by keywords and time intervals\n- **Event analytics** with count and total duration calculation\n- **Personalization** through keyword system and calendar selection\n- **OAuth authorization** for Google Calendar with secure token storage\n- **Data caching** for performance optimization\n\n### Key Features:\n\n- Voice command recognition in multiple languages (via AssemblyAI)\n- Intelligent text analysis (via OpenAI API)\n- Automatic extraction of dates, times, and descriptions from natural language\n- Keyword system (regular, compound, default)\n- Automatic OAuth token refresh\n- User data and session caching\n\n---\n\n## 2. Commands And Features\n\n### Main Commands\n\n- `/start` - Start working with the bot, configure Google Calendar authorization\n- `/help` - Get help on using the bot\n- `/setting` - Open settings (authorization, calendar, keywords)\n- `/analytics` - Request event analytics\n- `/search` - Search events in calendar\n\n### Event Creation\n\n#### Text Format:\n```\n31.01.2024 12:00 Meeting with team\n```\n\nFormat: `dd.MM.yyyy HH:mm Description`\n\n#### Voice Format:\nYou can send voice messages in free form, for example:\n- \"Meeting tomorrow at 14:00 for one hour\"\n- \"Add event the day after tomorrow in the evening at 7 o'clock, duration 2 hours, meeting with client\"\n- \"Tomorrow morning at 10:30 meeting with team for one and a half hours\"\n\n**Features:**\n- Date can be specified in free form: \"tomorrow\", \"the day after tomorrow\", \"in a week\", etc.\n- Time can be specified in words: \"at eight\", \"at ten in the evening\", \"at 19:00\"\n- Duration can be specified in words: \"for one hour\", \"for two hours\", \"from eight to ten\"\n\n### Event Search\n\n#### Text Format:\n```\n2024-01-01 / 2024-01-31 / all / Meeting\n```\n\nFormat: `yyyy-MM-dd / yyyy-MM-dd / [first|last|all] / [Keyword]`\n\nParameters:\n- First date - start of period\n- Second date - end of period  \n- Search type: `first` (first), `last` (last), `all` (all)\n- Keyword (optional)\n\n#### Voice Format:\nYou can send voice messages in free form, for example:\n- \"Find all meetings in January\"\n- \"Find the first event with keyword 'meeting' from last month\"\n\n### Analytics\n\n#### Text Format:\n```\n2024-01-01 2024-01-31 Meeting\n```\n\nFormat: `yyyy-MM-dd yyyy-MM-dd [Keyword]`\n\nThe bot will return:\n- Number of events\n- Total duration in hours\n\n#### Voice Format:\nYou can send voice messages in free form, for example:\n- \"Show analytics for last month\"\n- \"How much time did I spend on meetings in January\"\n\n### Settings\n\nAvailable settings (via `/setting`):\n\n1. **Connection settings** - Google Calendar authorization setup\n   - OAuth authorization link\n   - Calendar selection from available list\n\n2. **Keywords** - Keyword configuration\n   - Keywords are added to the beginning of event description\n   - Example: with keyword \"Mike\", event \"tomorrow at 11 go to store, Mike\" \n     will create an event with description \"Mike. Go to store\"\n\n3. **Default keyword** - Default keyword\n   - Automatically set if keyword is not specified\n\n4. **Compound keywords** - Compound keywords\n   - Groups of words that are considered one keyword\n   - Format: \"Partner1 Partner2, My family\"\n   - \"Partner1 Partner2\" and \"My family\" will be recognized as separate keywords\n\n5. **Clear all keywords** - Clear all keywords\n\n6. **Request Access** - Access request (for new users)\n   - Sends request to administrator\n\n---\n\n## 3. Architecture And Project Structure\n\n### Technology Stack\n\n- **Backend Framework**: Spring Boot 3.4.0\n- **Java Version**: 17\n- **Build Tool**: Maven\n- **Database**: PostgreSQL\n- **Caching**: Caffeine\n- **ORM**: Spring Data JPA / Hibernate\n- **External APIs**:\n  - Google Calendar API (OAuth 2.0)\n  - OpenAI API (ChatGPT)\n  - AssemblyAI API (Speech-to-Text)\n  - Telegram Bot API\n\n### Project Structure\n\n```\ntelegram-calendar-base/\n├── src/\n│   ├── main/\n│   │   ├── java/krpaivin/telcal/\n│   │   │   ├── calendar/           # Google Calendar integration\n│   │   │   │   ├── GoogleCalendarService.java\n│   │   │   │   └── SearchType.java\n│   │   │   ├── chatgpt/            # OpenAI integration\n│   │   │   │   ├── ChatGPTHadler.java\n│   │   │   │   └── TypeGPTRequest.java\n│   │   │   ├── config/             # Configuration\n│   │   │   │   ├── CacheConfig.java\n│   │   │   │   ├── Constants.java\n│   │   │   │   ├── CredentialsManager.java\n│   │   │   │   ├── Messages.java\n│   │   │   │   └── TelegramProperties.java\n│   │   │   ├── data/               # User data management\n│   │   │   │   ├── CredentialsLoader.java\n│   │   │   │   └── UserAuthData.java\n│   │   │   ├── entity/             # JPA entities\n│   │   │   │   ├── UserData.java\n│   │   │   │   ├── UserDataRepository.java\n│   │   │   │   └── UserDataService.java\n│   │   │   ├── telegram/           # Telegram bot logic\n│   │   │   │   ├── TelegramCalendar.java\n│   │   │   │   ├── VoiceCommandHandler.java\n│   │   │   │   ├── TextHandler.java\n│   │   │   │   └── CalendarDataService.java\n│   │   │   └── Main.java           # Entry point\n│   │   └── resources/\n│   │       ├── application.properties\n│   │       └── config/\n│   │           └── credentials.json  # Not in git (.gitignore)\n│   └── test/\n├── infra/                          # AWS CloudFormation templates\n│   ├── telegram-calendar-docker.yaml  # Full stack: EC2 + Docker + RDS\n│   └── telegram-calendar-rds.yaml    # RDS only (optional)\n├── Dockerfile                      # Multi-stage Docker build\n└── pom.xml\n```\n\n### Key Components\n\n#### TelegramCalendar\nMain bot class, handles incoming messages and callback queries.\n\n#### GoogleCalendarService\nService for working with Google Calendar API:\n- Event creation\n- Event search\n- Analytics\n- Authorization management\n\n#### ChatGPTHandler\nProcessing requests to OpenAI API for text analysis and data extraction.\n\n#### VoiceCommandHandler\nConverting voice messages to text via AssemblyAI.\n\n#### CalendarDataService\nOrchestrating event creation, search, and analytics processes.\n\n#### UserAuthData\nManaging user data, tokens, and keywords.\n\n#### CacheConfig\nCache configuration:\n- User data cache (1 hour, up to 100 entries)\n- Session data cache (1 hour, up to 300 entries)\n- Calendar selection cache (1 hour, up to 300 entries)\n\n---\n\n## 4. Configuration\n\n### application.properties File\n\nAll settings are in `src/main/resources/application.properties`:\n\n```properties\n# Main settings\nspring.main.web-application-type=none\nbotToken=\u003cYOUR_TELEGRAM_BOT_TOKEN\u003e\nassemblyAI=\u003cYOUR_ASSEMBLYAI_API_KEY\u003e\nopenAIKey=\u003cYOUR_OPENAI_API_KEY\u003e\nopenAIURL=https://api.openai.com/v1/chat/completions\nassemblyAIURL=https://api.assemblyai.com/v2/upload\n\n# Maintenance mode settings\nmaintenanceMode=false  # true - maintenance mode enabled\nuserOneId=\u003cTELEGRAM_USERNAME\u003e  # User with access in maintenance mode\nadminChatid=\u003cTELEGRAM_CHAT_ID\u003e  # Administrator chat ID\n\n# PostgreSQL database\nspring.datasource.url=jdbc:postgresql://host:port/database\nspring.datasource.username=postgres\nspring.datasource.password=password\nspring.datasource.driver-class-name=org.postgresql.Driver\nspring.jpa.database=postgresql\nspring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect\n```\n\n### Maintenance Mode\n\nWith `maintenanceMode=true`, the bot is only available to the user specified in `userOneId`.\nOther users will receive an unavailability message.\n\n### Google OAuth Setup\n\n1. Create a project in Google Cloud Console\n2. Enable Google Calendar API\n3. Create OAuth 2.0 Client ID (type: Desktop app)\n4. Download JSON file with credentials\n5. Rename to `credentials.json` and place in `src/main/resources/config/`\n6. Add your Gmail to Test Users in the project\n\n**Important:** The `credentials.json` file is in `.gitignore` and will not be committed to the repository. For AWS deployment, you need to upload this file separately to the EC2 instance (see AWS Deployment section).\n\n### Database Structure\n\n`user_data` table:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| id | BIGINT | Primary key (auto-increment) |\n| user_id | TEXT | Telegram username (unique) |\n| version | BIGINT | Version for optimistic locking |\n| access_token | TEXT | Google OAuth access token |\n| refresh_token | TEXT | Google OAuth refresh token |\n| expiration_time_token | TEXT | Access token expiration time |\n| calendar | TEXT | The identifier of the user's Google Calendar |\n| keywords | TEXT | A list of keywords |\n| default_keyword | TEXT | The default keyword |\n| compound_keywords | TEXT | A list of compound keywords |\n\n### Table Creation SQL Script\n\n```sql\nCREATE TABLE user_data (\n    id BIGSERIAL PRIMARY KEY,\n    user_id TEXT NOT NULL UNIQUE,\n    version BIGINT DEFAULT 0,\n    access_token TEXT,\n    refresh_token TEXT,\n    expiration_time_token TEXT,\n    calendar TEXT,\n    keywords TEXT,\n    default_keyword TEXT,\n    compound_keywords TEXT\n);\n```\n\n---\n\n## 5. Deployment\n\n### Local Development\n\n1. **Clone the repository**\n```bash\ngit clone \u003crepository-url\u003e\ncd telegram-calendar-base\n```\n\n2. **Set up the database**\n   - Install PostgreSQL\n   - Create a database\n   - Execute the table creation SQL script\n\n3. **Configure application.properties**\n   - Add all necessary API keys\n   - Configure database connection\n\n4. **Set up Google OAuth**\n   - Place `credentials.json` in `src/main/resources/config/`\n\n5. **Build the project**\n```bash\nmvn clean package\n```\n\n6. **Run the application**\n```bash\njava -jar target/telegram-calendar-1.0-SNAPSHOT.jar\n```\n\n### AWS Deployment\n\nThe project is configured for deployment on AWS using **Docker** and **CloudFormation**:\n- **EC2** - for running the application in Docker container\n- **RDS** - for PostgreSQL database\n- **CloudFormation** - for infrastructure as code\n\n#### Prerequisites\n\n1. **AWS CLI** installed and configured\n2. **AWS Account** with appropriate permissions\n3. **EC2 Key Pair** for SSH access\n4. **GitHub repository** with the project code\n\n#### Deployment Steps\n\n##### 1. Prepare CloudFormation Template\n\nThe CloudFormation template is located in `infra/telegram-calendar-docker.yaml`. It includes:\n- EC2 instance with Docker\n- RDS PostgreSQL database\n- Security Groups\n- IAM Roles\n- Automatic deployment via git clone and docker build\n\n**Important parameters in the template:**\n- `GitRepoUrl` - Your GitHub repository URL\n- `BotToken`, `OpenAIKey`, `AssemblyAIKey` - API keys\n- `VpcId`, `PublicSubnetId`, `DbSubnet1`, `DbSubnet2` - Network configuration\n- `KeyName` - EC2 Key Pair name\n\n##### 2. Validate CloudFormation Template\n\n```bash\naws cloudformation validate-template \\\n  --template-body file://infra/telegram-calendar-docker.yaml \\\n  --region us-east-1\n```\n\n##### 3. Create Change Set\n\n```bash\naws cloudformation create-change-set \\\n  --stack-name telegram-calendar-docker \\\n  --change-set-name telegram-calendar-docker-initial \\\n  --change-set-type CREATE \\\n  --template-body file://infra/telegram-calendar-docker.yaml \\\n  --capabilities CAPABILITY_IAM \\\n  --region us-east-1\n```\n\n##### 4. Execute Change Set\n\n```bash\naws cloudformation execute-change-set \\\n  --stack-name telegram-calendar-docker \\\n  --change-set-name telegram-calendar-docker-initial \\\n  --region us-east-1\n```\n\n##### 5. Wait for Stack Creation\n\n```bash\naws cloudformation wait stack-create-complete \\\n  --stack-name telegram-calendar-docker \\\n  --region us-east-1\n```\n\n##### 6. Get Stack Outputs\n\n```bash\naws cloudformation describe-stacks \\\n  --stack-name telegram-calendar-docker \\\n  --query \"Stacks[0].Outputs\" \\\n  --region us-east-1\n```\n\nThis will return:\n- `PublicIP` - EC2 instance public IP\n- `RdsEndpoint` - RDS database endpoint\n- `InstanceId` - EC2 instance ID\n\n##### 7. Create Database Table\n\nConnect to EC2 and then to RDS:\n\n```bash\n# SSH to EC2\nssh -i \u003cpath-to-key\u003e.pem ec2-user@\u003cPublicIP\u003e\n\n# Install PostgreSQL client\nsudo yum install -y postgresql15\n\n# Connect to RDS and create table\nPGPASSWORD='\u003cdb-password\u003e' psql -h \u003cRdsEndpoint\u003e -p 5432 -d db_calendar -U postgres\n```\n\nIn psql, execute:\n\n```sql\nCREATE TABLE user_data (\n    id BIGSERIAL PRIMARY KEY,\n    user_id TEXT NOT NULL UNIQUE,\n    version BIGINT DEFAULT 0,\n    access_token TEXT,\n    refresh_token TEXT,\n    expiration_time_token TEXT,\n    calendar TEXT,\n    keywords TEXT,\n    default_keyword TEXT,\n    compound_keywords TEXT\n);\n```\n\n##### 8. Upload credentials.json\n\nThe `credentials.json` file is not in the repository (`.gitignore`). Upload it to EC2:\n\n```bash\n# Create directory\nssh -i \u003cpath-to-key\u003e.pem ec2-user@\u003cPublicIP\u003e \"mkdir -p /home/ec2-user/app/src/main/resources/config\"\n\n# Upload file\nscp -i \u003cpath-to-key\u003e.pem \\\n  src/main/resources/config/credentials.json \\\n  ec2-user@\u003cPublicIP\u003e:/home/ec2-user/app/src/main/resources/config/credentials.json\n```\n\n##### 9. Rebuild and Restart Docker Container\n\nOn EC2 instance:\n\n```bash\ncd /home/ec2-user/app\ndocker stop telegram-calendar-backend\ndocker rm telegram-calendar-backend\ndocker build -t telegram-calendar-backend .\ndocker run -d --name telegram-calendar-backend --restart always \\\n  -e BOT_TOKEN=\u003cyour-bot-token\u003e \\\n  -e ASSEMBLYAI=\u003cyour-assemblyai-key\u003e \\\n  -e OPENAIKEY=\u003cyour-openai-key\u003e \\\n  -e OPENAIURL=https://api.openai.com/v1/chat/completions \\\n  -e ASSEMBLYAIURL=https://api.assemblyai.com/v2/upload \\\n  -e MAINTENANCEMODE=false \\\n  -e USERONEID=\u003cyour-telegram-username\u003e \\\n  -e ADMINCHATID=\u003cyour-admin-chat-id\u003e \\\n  -e CALENDARID=\u003cyour-calendar-id\u003e \\\n  -e SPRING_DATASOURCE_URL=jdbc:postgresql://\u003cRdsEndpoint\u003e:5432/db_calendar \\\n  -e SPRING_DATASOURCE_USERNAME=postgres \\\n  -e SPRING_DATASOURCE_PASSWORD='\u003cdb-password\u003e' \\\n  -e SPRING_DATASOURCE_DRIVER_CLASS_NAME=org.postgresql.Driver \\\n  -e SPRING_JPA_DATABASE=postgresql \\\n  -e SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.PostgreSQLDialect \\\n  telegram-calendar-backend\n```\n\n##### 10. Check Container Status\n\n```bash\ndocker ps\ndocker logs -f telegram-calendar-backend\n```\n\n#### Docker Configuration\n\nThe application runs in a Docker container with environment variables. All configuration is passed via environment variables, overriding `application.properties` values.\n\n**Environment Variables:**\n- `BOT_TOKEN` - Telegram bot token\n- `ASSEMBLYAI` - AssemblyAI API key\n- `OPENAIKEY` - OpenAI API key\n- `OPENAIURL` - OpenAI API endpoint\n- `ASSEMBLYAIURL` - AssemblyAI API endpoint\n- `MAINTENANCEMODE` - Maintenance mode flag\n- `USERONEID` - Telegram username for maintenance mode\n- `ADMINCHATID` - Administrator chat ID\n- `CALENDARID` - Google Calendar ID\n- `SPRING_DATASOURCE_*` - Database connection parameters\n\n#### CloudFormation Template Details\n\nThe `infra/telegram-calendar-docker.yaml` template:\n- Creates EC2 instance (t3.micro by default, supports Free Tier)\n- Installs Docker and Git\n- Clones repository from GitHub\n- Builds Docker image\n- Runs container with all environment variables\n- Creates RDS PostgreSQL instance (db.t4g.micro, supports Free Tier)\n- Configures Security Groups for EC2 and RDS\n- Sets up IAM roles for EC2\n\n#### Troubleshooting\n\n**Container not starting:**\n```bash\ndocker logs telegram-calendar-backend\n```\n\n**Database connection issues:**\n- Check Security Group allows port 5432 from EC2\n- Verify RDS endpoint and credentials\n\n**credentials.json not found:**\n- Ensure file is uploaded to `/home/ec2-user/app/src/main/resources/config/`\n- Rebuild Docker image after uploading\n\n**Stack creation fails:**\n- Check CloudFormation events: `aws cloudformation describe-stack-events --stack-name telegram-calendar-docker`\n- Verify all parameters are correct\n- Ensure instance types are available in your region (Free Tier eligible)\n\n---\n\n## 6. Workflow Diagrams\n\n```mermaid\ngraph TD;\n    A[User sends a voice message] --\u003e B[Bot receives file via Telegram API];\n    B --\u003e C[AssemblyAI converts the file to text];\n    C --\u003e D[ChatGPT analyzes the text and returns a result];\n    D --\u003e E[Bot sends the result to the user for confirmation];\n    E --\u003e F{Does the user confirm the event?};\n    F -- Yes --\u003e G[Event is created in Google Calendar];\n    F -- No --\u003e H[Event creation is cancelled];\n\n```\n\n---\n\n## 7. Usage Examples\n\n### Example 1: Creating Event via Text\n```\nUser: 31.01.2024 14:00 Meeting with team\nBot: Event created in Google Calendar.\n```\n\n### Example 2: Creating Event via Voice\n```\nUser: [voice] \"Tomorrow at 10 AM meeting with client for one hour\"\nBot: Will be created:\n     2024-01-31 10:00 / Duration=60 / Meeting with client\n     [Confirm] [Cancel]\n```\n\n### Example 3: Event Search\n```\nUser: /search\nBot: Send message with period, keyword (optional) and type search (optional).\nUser: [voice] \"Find all meetings in January\"\nBot: Events found:\n     Date = 2024-01-15 14:00, Duration = 1, Description = Meeting with team\n     ...\n```\n\n### Example 4: Analytics\n```\nUser: /analytics\nBot: Send message with period and keyword (optional).\nUser: 2024-01-01 2024-01-31 Meeting\nBot: Amount events: 10.\n     All time (hours): 15\n```\n\n## 8. FAQ\n\n**Q: Can I use multiple calendars?**\nA: The bot only supports creating events in the specified calendar, but you can change the calendar, use `/setting` → \"Connection settings\".\n\n**Q: Are recurring events supported?**\nA: The current version only supports creating one-time events.\n\n**Q: How to change GPT model?**\nA: Change the `GPT_MODEL` constant in `Constants.java`.\n\n**Q: Can I use the bot in multiple languages?**\nA: Yes, the bot supports voice messages in different languages via AssemblyAI.\n\n## 9. License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favkrapivin%2Ftelegram-calendar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Favkrapivin%2Ftelegram-calendar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Favkrapivin%2Ftelegram-calendar/lists"}